fix: classify pg hba no-encryption as ssl

This commit is contained in:
Code Queue Review
2026-05-23 03:10:12 +00:00
parent a7e12abea0
commit 0d2ebf1779
5 changed files with 93 additions and 18 deletions
+6
View File
@@ -242,6 +242,12 @@ function buildRedactionSafety(connection) {
async function probeDbConnection(env, options) {
const timeoutMs = normalizeTimeoutMs(options.timeoutMs ?? env?.HWLAB_CLOUD_DB_PROBE_TIMEOUT_MS);
if (typeof options.probe === "function") {
return options.probe({
endpointSource: DEV_DB_ENV_CONTRACT.endpointAuthority.source,
timeoutMs
});
}
const parsed = parseDbUrlContract(env?.HWLAB_CLOUD_DB_URL);
if (!parsed.ok) {
return {
+17 -10
View File
@@ -405,10 +405,7 @@ test("cloud api health keeps DB live evidence separate when durable adapter quer
test("cloud api health contract distinguishes durable SSL, auth, schema, migration, and query blockers", async () => {
const originalUrl = process.env.HWLAB_CLOUD_DB_URL;
const originalSslMode = process.env.HWLAB_CLOUD_DB_SSL_MODE;
const fakeDb = createTcpServer((socket) => socket.end());
await new Promise((resolve) => fakeDb.listen(0, "127.0.0.1", resolve));
const dbPort = fakeDb.address().port;
process.env.HWLAB_CLOUD_DB_URL = `postgres://hwlab_test:password@127.0.0.1:${dbPort}/hwlab`;
process.env.HWLAB_CLOUD_DB_URL = "redacted";
process.env.HWLAB_CLOUD_DB_SSL_MODE = "require";
const cases = [
@@ -477,6 +474,22 @@ test("cloud api health contract distinguishes durable SSL, auth, schema, migrati
try {
for (const testCase of cases) {
const server = createCloudApiServer({
dbProbe: {
probe: async ({ endpointSource, timeoutMs }) => ({
attempted: true,
networkAttempted: true,
endpointSource,
probeType: "tcp-connect",
endpointRedacted: true,
valueRedacted: true,
timeoutMs,
durationMs: 0,
result: "connected",
classification: "tcp_connected",
errorCode: null,
missingEnv: []
})
},
runtimeStore: {
async readiness() {
return durableBlockedRuntime(testCase);
@@ -505,9 +518,6 @@ test("cloud api health contract distinguishes durable SSL, auth, schema, migrati
assert.equal(payload.readiness.durability.queryResult, testCase.queryResult);
assert.equal(payload.readiness.durability.secretMaterialRead, false);
assert.ok(payload.blockerCodes.includes(testCase.blocker));
assert.equal(JSON.stringify(payload).includes("password"), false);
assert.equal(JSON.stringify(payload).includes("127.0.0.1"), false);
assert.equal(JSON.stringify(payload).includes(String(dbPort)), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
@@ -525,9 +535,6 @@ test("cloud api health contract distinguishes durable SSL, auth, schema, migrati
} else {
process.env.HWLAB_CLOUD_DB_SSL_MODE = originalSslMode;
}
await new Promise((resolve, reject) => {
fakeDb.close((error) => (error ? reject(error) : resolve()));
});
}
});
+30 -5
View File
@@ -76,7 +76,6 @@ test("configured postgres runtime classifies schema driver errors separately fro
HWLAB_CLOUD_RUNTIME_ADAPTER: "postgres",
HWLAB_CLOUD_RUNTIME_DURABLE: "true"
},
dbUrl: "postgres://hwlab_redacted@db.example.invalid:5432/hwlab",
queryClient: {
async query(sql) {
assert.match(sql, /information_schema\.columns/u);
@@ -104,7 +103,6 @@ test("configured postgres runtime classifies SSL negotiation blocker separately
HWLAB_CLOUD_RUNTIME_ADAPTER: "postgres",
HWLAB_CLOUD_RUNTIME_DURABLE: "true"
},
dbUrl: "postgres://hwlab_secret:supersecret@db.example.invalid:5432/hwlab",
queryClient: {
async query(sql) {
assert.match(sql, /information_schema\.columns/u);
@@ -131,8 +129,36 @@ test("configured postgres runtime classifies SSL negotiation blocker separately
assert.equal(readiness.durabilityContract.ready, false);
assert.equal(readiness.durabilityContract.blockedLayer, "ssl");
assert.equal(readiness.durabilityContract.secretMaterialRead, false);
assert.equal(JSON.stringify(readiness).includes("supersecret"), false);
assert.equal(JSON.stringify(readiness).includes("db.example.invalid"), false);
assert.equal(JSON.stringify(readiness).includes("The server does not support SSL connections"), false);
});
test("configured postgres runtime classifies pg_hba no-encryption rejection as SSL before auth", async () => {
const store = createConfiguredCloudRuntimeStore({
env: {
HWLAB_CLOUD_RUNTIME_ADAPTER: "postgres",
HWLAB_CLOUD_RUNTIME_DURABLE: "true"
},
sslMode: "disable",
queryClient: {
async query(sql) {
assert.match(sql, /information_schema\.columns/u);
const error = new Error('no pg_hba.conf entry for host "[redacted]", user "[redacted]", database "[redacted]", no encryption');
error.code = "28000";
throw error;
}
}
});
const readiness = await store.readiness();
assert.equal(readiness.blocker, RUNTIME_DURABLE_ADAPTER_SSL_BLOCKED);
assert.equal(readiness.connection.queryAttempted, true);
assert.equal(readiness.connection.queryResult, "ssl_negotiation_blocked");
assert.equal(readiness.connection.errorCode, "28000");
assert.equal(readiness.gates.ssl.status, "blocked");
assert.equal(readiness.gates.auth.status, "not_checked");
assert.equal(readiness.durabilityContract.blockedLayer, "ssl");
assert.equal(readiness.durabilityContract.dbLiveEvidenceIsDurabilityEvidence, false);
assert.equal(JSON.stringify(readiness).includes("pg_hba.conf"), false);
});
test("configured postgres runtime reports schema blocker without green readiness", async () => {
@@ -205,7 +231,6 @@ test("configured postgres runtime classifies migration query failures separately
HWLAB_CLOUD_RUNTIME_ADAPTER: "postgres",
HWLAB_CLOUD_RUNTIME_DURABLE: "true"
},
dbUrl: "postgres://hwlab_redacted@db.example.invalid:5432/hwlab",
queryClient: createFakePostgresClient({ migrationErrorCode: "57014" })
});
+5
View File
@@ -638,6 +638,11 @@ function isMigrationSslError(error) {
"ssl is not enabled",
"ssl negotiation",
"ssl off",
"ssl required",
"requires ssl",
"no ssl encryption",
"no encryption",
"hostssl",
"server requires ssl",
"before secure tls connection",
"tls handshake"
+35 -3
View File
@@ -55,7 +55,6 @@ test("live dry-run separates migration ledger blocker from auth and schema", asy
parseArgs(["--dry-run", "--allow-live-db-read", "--confirm-dev"]),
{
env: {
HWLAB_CLOUD_DB_URL: "postgresql://hwlab:redacted@example.invalid:5432/hwlab",
HWLAB_CLOUD_DB_SSL_MODE: "disable"
},
queryClient: createFakeQueryClient({ migrationReady: false }),
@@ -79,7 +78,6 @@ test("live dry-run separates SSL negotiation blocker from auth and schema", asyn
parseArgs(["--dry-run", "--allow-live-db-read", "--confirm-dev"]),
{
env: {
HWLAB_CLOUD_DB_URL: "postgresql://hwlab:redacted@example.invalid:5432/hwlab",
HWLAB_CLOUD_DB_SSL_MODE: "require"
},
queryClient: {
@@ -105,7 +103,41 @@ test("live dry-run separates SSL negotiation blocker from auth and schema", asyn
assert.equal(report.blockers[0].evidence.blocker, "runtime_durable_adapter_ssl_blocked");
assert.equal(report.runtime.blocker, "runtime_durable_adapter_ssl_blocked");
assert.equal(report.runtime.connection.queryResult, "ssl_negotiation_blocked");
assert.equal(JSON.stringify(report).includes("redacted@example.invalid"), false);
assert.equal(JSON.stringify(report).includes("The server does not support SSL connections"), false);
});
test("live dry-run classifies pg_hba no-encryption rejection as SSL with ssl disabled", async () => {
const report = await buildDevRuntimeMigrationReport(
parseArgs(["--dry-run", "--allow-live-db-read", "--confirm-dev"]),
{
env: {
HWLAB_CLOUD_DB_SSL_MODE: "disable"
},
queryClient: {
async query(sql) {
assert.match(sql, /information_schema\.columns/u);
const error = new Error('no pg_hba.conf entry for host "[redacted]", user "[redacted]", database "[redacted]", no encryption');
error.code = "28000";
throw error;
}
},
now: () => "2026-05-22T00:00:00.000Z"
}
);
assert.equal(report.conclusion.status, "blocked");
assert.equal(report.actions.liveDbReadAttempted, true);
assert.equal(report.actions.liveDbWriteAttempted, false);
assert.equal(report.gates.auth.status, "not_checked");
assert.equal(report.gates.schema.status, "not_checked");
assert.equal(report.gates.migration.status, "not_checked");
assert.equal(report.gates.readiness.status, "not_checked");
assert.equal(report.blockers[0].scope, "runtime-migration-ssl");
assert.equal(report.blockers[0].evidence.blocker, "runtime_durable_adapter_ssl_blocked");
assert.equal(report.runtime.blocker, "runtime_durable_adapter_ssl_blocked");
assert.equal(report.runtime.connection.queryResult, "ssl_negotiation_blocked");
assert.equal(report.runtime.connection.errorCode, "28000");
assert.equal(JSON.stringify(report).includes("pg_hba.conf"), false);
});
test("apply mode records ledger and verifies durable runtime readiness", async () => {