Merge PR #226: disable DEV cloud-api DB SSL mode

Host commander review: source-only desired-state/contract fix for #164 runtime durable blocker. Diff switches DEV HWLAB_CLOUD_DB_SSL_MODE from require to disable across deploy manifest, rendered workload, schema, docs, validators, deploy/preflight guards, and tests. No Secret values, live cluster mutation, deploy, restart, or DB write in the PR evidence. Controlled DEV rollout remains separate via Code Queue.
This commit is contained in:
Lyon
2026-05-23 10:32:40 +08:00
committed by GitHub
17 changed files with 231 additions and 28 deletions
+1 -1
View File
@@ -18,7 +18,7 @@ for future compatibility, but PROD deployment is not part of MVP acceptance.
- `hwlab-cloud-api` declares the DEV DB env contract with
`HWLAB_CLOUD_DB_URL` from Secret reference
`hwlab-cloud-api-dev-db/database-url` and non-secret
`HWLAB_CLOUD_DB_SSL_MODE=require`. Runtime DB readiness dials the redacted
`HWLAB_CLOUD_DB_SSL_MODE=disable`. Runtime DB readiness dials the redacted
host parsed from that Secret URL. `cloud-api-db` is only an optional desired
alias until Service plus Endpoint/EndpointSlice ownership and rollout/apply
contract exist; see
+1 -1
View File
@@ -194,7 +194,7 @@
"HWLAB_IMAGE_TAG": "7de6edd",
"HWLAB_RUNTIME_SUBSTITUTE_FORBIDDEN": "unidesk-backend,provider-gateway,microservice-proxy",
"HWLAB_CLOUD_DB_URL": "secretRef:hwlab-cloud-api-dev-db/database-url",
"HWLAB_CLOUD_DB_SSL_MODE": "require",
"HWLAB_CLOUD_DB_SSL_MODE": "disable",
"HWLAB_CLOUD_DB_CONTRACT": "dev-redacted-presence-only",
"HWLAB_CLOUD_RUNTIME_ADAPTER": "postgres",
"HWLAB_CLOUD_RUNTIME_DURABLE": "true",
+1 -1
View File
@@ -365,7 +365,7 @@
},
"HWLAB_CLOUD_DB_SSL_MODE": {
"type": "string",
"const": "require"
"const": "disable"
},
"HWLAB_CLOUD_DB_CONTRACT": {
"type": "string",
+1 -1
View File
@@ -75,7 +75,7 @@
},
{
"name": "HWLAB_CLOUD_DB_SSL_MODE",
"value": "require"
"value": "disable"
},
{
"name": "HWLAB_CLOUD_DB_CONTRACT",
+1 -1
View File
@@ -12,7 +12,7 @@
"data": {
"endpoint": "http://74.48.78.17:16667",
"cloud-api": "GET /health/live via hwlab-edge-proxy then hwlab-cloud-api:6667",
"cloud-api-db": "DEV DB config gate requires HWLAB_CLOUD_DB_URL from Secret hwlab-cloud-api-dev-db/database-url and HWLAB_CLOUD_DB_SSL_MODE=require. Runtime readiness dials the redacted host parsed from the Secret URL and reports endpointSource=secret-url-host. cloud-api-db is an optional desired alias only until this repo owns Service plus Endpoint or EndpointSlice manifests and rollout/apply contract; health reports env presence, env injection, redacted connection attempt/result, and liveConnected without exposing secret values",
"cloud-api-db": "DEV DB config gate requires HWLAB_CLOUD_DB_URL from Secret hwlab-cloud-api-dev-db/database-url and HWLAB_CLOUD_DB_SSL_MODE=disable. Runtime readiness dials the redacted host parsed from the Secret URL and reports endpointSource=secret-url-host. cloud-api-db is an optional desired alias only until this repo owns Service plus Endpoint or EndpointSlice manifests and rollout/apply contract; health reports env presence, env injection, redacted connection attempt/result, and liveConnected without exposing secret values",
"cloud-web": "GET /health/live on hwlab-cloud-web:8080; consumes cloud-api only",
"agent": "hwlab-agent-mgr readiness gates worker template creation; hwlab-agent-worker is suspended until a session is scheduled",
"sim": "hwlab-gateway-simu:7101 and hwlab-box-simu:7201 expose /health/live for DEV smoke",
+1 -1
View File
@@ -289,7 +289,7 @@ unchanged.
`hwlab-cloud-api` has a DEV DB env contract placeholder:
`HWLAB_CLOUD_DB_URL` must come from Secret reference
`hwlab-cloud-api-dev-db/database-url`, and
`HWLAB_CLOUD_DB_SSL_MODE=require`. Runtime readiness dials the redacted host
`HWLAB_CLOUD_DB_SSL_MODE=disable`. Runtime readiness dials the redacted host
parsed from that Secret URL. `cloud-api-db` remains an optional desired alias,
not a readiness gate or TCP probe target, until this repo owns its
Service/Endpoint rollout contract. The local health gate reports DB runtime
+1 -1
View File
@@ -35,7 +35,7 @@ Required DEV DB config names:
- `HWLAB_CLOUD_DB_URL` from Secret reference
`hwlab-cloud-api-dev-db/database-url`.
- `HWLAB_CLOUD_DB_SSL_MODE=require`.
- `HWLAB_CLOUD_DB_SSL_MODE=disable`.
- Runtime TCP dial target: the redacted host parsed from
`HWLAB_CLOUD_DB_URL`, reported as `endpointSource="secret-url-host"`.
+1 -1
View File
@@ -70,7 +70,7 @@ The preflight checks:
- `hwlab-cloud-api` declares the DEV DB env contract:
`HWLAB_CLOUD_DB_URL` from Secret reference
`hwlab-cloud-api-dev-db/database-url` and
`HWLAB_CLOUD_DB_SSL_MODE=require`. Runtime readiness dials the redacted host
`HWLAB_CLOUD_DB_SSL_MODE=disable`. Runtime readiness dials the redacted host
parsed from that Secret URL. `cloud-api-db` is an optional desired alias only
until this repo owns Service plus Endpoint or EndpointSlice manifests and
rollout/apply contract.
+1 -1
View File
@@ -40,7 +40,7 @@ export const DEV_DB_ENV_CONTRACT = Object.freeze({
"schema"
]),
nonSecretDefaults: Object.freeze({
HWLAB_CLOUD_DB_SSL_MODE: "require"
HWLAB_CLOUD_DB_SSL_MODE: "disable"
}),
forbidden: Object.freeze({
prodAllowed: false,
+4 -4
View File
@@ -122,7 +122,7 @@ test("cloud api health reports DB env presence and live connection classificatio
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@127.0.0.1:${dbPort}/hwlab`;
process.env.HWLAB_CLOUD_DB_SSL_MODE = "require";
process.env.HWLAB_CLOUD_DB_SSL_MODE = "disable";
delete process.env.HWLAB_CLOUD_DB_SERVICE_NAME;
delete process.env.HWLAB_CLOUD_DB_SERVICE_NAMESPACE;
delete process.env.HWLAB_CLOUD_DB_HOST;
@@ -213,7 +213,7 @@ test("cloud api health separates DB connected from durable runtime schema readin
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@127.0.0.1:${dbPort}/hwlab`;
process.env.HWLAB_CLOUD_DB_SSL_MODE = "require";
process.env.HWLAB_CLOUD_DB_SSL_MODE = "disable";
const server = createCloudApiServer({
runtimeStore: {
@@ -302,7 +302,7 @@ test("cloud api health keeps DB live evidence separate when durable adapter quer
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_SSL_MODE = "require";
process.env.HWLAB_CLOUD_DB_SSL_MODE = "disable";
const server = createCloudApiServer({
runtimeStore: {
@@ -404,7 +404,7 @@ test("cloud api health does not treat DB env presence-only as live readiness", a
const originalSslMode = process.env.HWLAB_CLOUD_DB_SSL_MODE;
const originalProbeDisabled = process.env.HWLAB_CLOUD_DB_PROBE_DISABLED;
process.env.HWLAB_CLOUD_DB_URL = "postgres://user:password@db.example.invalid:5432/hwlab";
process.env.HWLAB_CLOUD_DB_SSL_MODE = "require";
process.env.HWLAB_CLOUD_DB_SSL_MODE = "disable";
delete process.env.HWLAB_CLOUD_DB_PROBE_DISABLED;
const server = createCloudApiServer();
+47 -1
View File
@@ -18,13 +18,17 @@ async function makeFixture({
deployEnvMirrors = true,
deploySkillsCommitId = null,
deployCodeAgentProviderEnv = true,
deployDbEnv = true,
deployDbSslMode = "disable",
workloadTag = commitId,
workloadEnvCommitId = commitId,
workloadEnvImageTag = commitId,
workloadEnvImage = null,
workloadEnvMirrors = true,
workloadSkillsCommitId = null,
workloadCodeAgentProviderEnv = true
workloadCodeAgentProviderEnv = true,
workloadDbEnv = true,
workloadDbSslMode = "disable"
} = {}) {
const root = await mkdtemp(path.join(os.tmpdir(), "hwlab-desired-state-"));
await mkdir(path.join(root, "deploy/k8s/base"), { recursive: true });
@@ -59,6 +63,28 @@ async function makeFixture({
}
]
: [];
const dbEnv =
serviceId === "hwlab-cloud-api" && deployDbEnv
? {
HWLAB_CLOUD_DB_URL: "secretRef:hwlab-cloud-api-dev-db/database-url",
HWLAB_CLOUD_DB_SSL_MODE: deployDbSslMode
}
: {};
const workloadDbEntries =
serviceId === "hwlab-cloud-api" && workloadDbEnv
? [
{
name: "HWLAB_CLOUD_DB_URL",
valueFrom: {
secretKeyRef: {
name: "hwlab-cloud-api-dev-db",
key: "database-url"
}
}
},
{ name: "HWLAB_CLOUD_DB_SSL_MODE", value: workloadDbSslMode }
]
: [];
const deploy = {
manifestVersion: "v1",
environment: "dev",
@@ -77,6 +103,7 @@ async function makeFixture({
HWLAB_IMAGE: deployEnvImage ?? image,
HWLAB_IMAGE_TAG: deployEnvImageTag,
...(deploySkillsCommitId ? { HWLAB_SKILLS_COMMIT_ID: deploySkillsCommitId } : {}),
...dbEnv,
...providerEnv
}
: {}
@@ -136,6 +163,7 @@ async function makeFixture({
{ name: "HWLAB_IMAGE", value: workloadEnvImage ?? image },
{ name: "HWLAB_IMAGE_TAG", value: workloadEnvImageTag },
...(workloadSkillsCommitId ? [{ name: "HWLAB_SKILLS_COMMIT_ID", value: workloadSkillsCommitId }] : []),
...workloadDbEntries,
...workloadProviderEnv
]
: []
@@ -174,12 +202,30 @@ test("passes when cloud-api preserves provider env and DEV egress contract", asy
const repoRoot = await makeFixture();
const plan = await buildDesiredStatePlan({ repoRoot });
assert.equal(plan.status, "pass");
assert.equal(plan.cloudApiDb.ready, true);
assert.equal(plan.cloudApiDb.sslMode.expected, "disable");
assert.equal(plan.cloudApiDb.sslMode.deployMatches, true);
assert.equal(plan.cloudApiDb.sslMode.workloadMatches, true);
assert.equal(plan.codeAgentProvider.ready, true);
assert.equal(plan.codeAgentProvider.secretRef.present, true);
assert.equal(plan.codeAgentProvider.egress.deployMatchesDevProxy, true);
assert.deepEqual(plan.diagnostics, []);
});
test("blocks when cloud-api DB SSL mode drifts back to require", async () => {
const repoRoot = await makeFixture({
deployDbSslMode: "require",
workloadDbSslMode: "require"
});
const plan = await buildDesiredStatePlan({ repoRoot });
assert.equal(plan.status, "blocked");
assert.equal(plan.cloudApiDb.ready, false);
assert.equal(plan.cloudApiDb.sslMode.expected, "disable");
assert.equal(plan.cloudApiDb.sslMode.deployMatches, false);
assert.equal(plan.cloudApiDb.sslMode.workloadMatches, false);
assert.ok(plan.diagnostics.some((diagnostic) => diagnostic.code === "cloud_api_db_contract_mismatch"));
});
test("blocks when cloud-web runtime identity mirrors are missing", async () => {
const repoRoot = await makeFixture({
serviceId: "hwlab-cloud-web",
+14 -1
View File
@@ -192,7 +192,13 @@ function validateSource(ctx, manifest) {
function validateCloudApiDbSource(ctx, env) {
const alias = DEV_DB_ENV_CONTRACT.dns;
expectEqual(ctx, env.HWLAB_CLOUD_DB_URL, "secretRef:hwlab-cloud-api-dev-db/database-url", "$.services.hwlab-cloud-api.env.HWLAB_CLOUD_DB_URL", "cloud API DB URL Secret reference");
expectEqual(ctx, env.HWLAB_CLOUD_DB_SSL_MODE, "require", "$.services.hwlab-cloud-api.env.HWLAB_CLOUD_DB_SSL_MODE", "cloud API DB SSL mode");
expectEqual(
ctx,
env.HWLAB_CLOUD_DB_SSL_MODE,
DEV_DB_ENV_CONTRACT.nonSecretDefaults.HWLAB_CLOUD_DB_SSL_MODE,
"$.services.hwlab-cloud-api.env.HWLAB_CLOUD_DB_SSL_MODE",
"cloud API DEV DB SSL mode"
);
expectEqual(ctx, env.HWLAB_CLOUD_DB_CONTRACT, "dev-redacted-presence-only", "$.services.hwlab-cloud-api.env.HWLAB_CLOUD_DB_CONTRACT", "cloud API DB redacted contract marker");
expectEqual(ctx, DEV_DB_ENV_CONTRACT.endpointAuthority.source, "secret-url-host", "internal/cloud/db-contract.mjs.endpointAuthority.source", "cloud API DB runtime authority source");
expectEqual(ctx, DEV_DB_ENV_CONTRACT.endpointAuthority.env, "HWLAB_CLOUD_DB_URL", "internal/cloud/db-contract.mjs.endpointAuthority.env", "cloud API DB runtime authority env");
@@ -343,6 +349,13 @@ function validateCloudApiDbOptionalAliasArtifacts(ctx, services, workloads) {
expectEqual(ctx, service, undefined, "deploy/k8s/base/services.yaml.cloud-api-db", "cloud-api-db remains optional until Service/Endpoint ownership and rollout contract exist");
const container = mapByServiceId(listItems(workloads)).get("hwlab-cloud-api")?.spec?.template?.spec?.containers?.[0];
const env = new Map((container?.env ?? []).map((entry) => [entry.name, entry.value]));
expectEqual(
ctx,
env.get("HWLAB_CLOUD_DB_SSL_MODE"),
DEV_DB_ENV_CONTRACT.nonSecretDefaults.HWLAB_CLOUD_DB_SSL_MODE,
"deploy/k8s/base/workloads.yaml.hwlab-cloud-api.env.HWLAB_CLOUD_DB_SSL_MODE",
"cloud API workload DEV DB SSL mode"
);
for (const name of [
"HWLAB_CLOUD_DB_SERVICE_NAME",
"HWLAB_CLOUD_DB_SERVICE_NAMESPACE",
+104
View File
@@ -8,6 +8,7 @@ import {
DEV_CODE_AGENT_PROVIDER_CONTRACT,
inspectCodeAgentProviderManifestRefs
} from "../../internal/cloud/code-agent-contract.mjs";
import { DEV_DB_ENV_CONTRACT } from "../../internal/cloud/db-contract.mjs";
const execFileAsync = promisify(execFile);
const defaultRepoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
@@ -329,6 +330,100 @@ function inspectCodeAgentProviderDesiredState(ctx, deployService, workloadRecord
return inspection;
}
function dbSecretRefPlaceholder() {
const ref = DEV_DB_ENV_CONTRACT.secretRefs[0];
return `secretRef:${ref.secretName}/${ref.secretKey}`;
}
function secretRefMatches(entry, ref) {
return (
entry?.valueFrom?.secretKeyRef?.name === ref.secretName &&
entry?.valueFrom?.secretKeyRef?.key === ref.secretKey
);
}
function inspectCloudApiDbDesiredState(ctx, deployService, workloadRecords) {
const workloadRecord = workloadRecords.find((workload) => workload.containerName === "hwlab-cloud-api") ?? workloadRecords[0] ?? null;
const deployEnv = deployService?.env ?? {};
const workloadEnv = workloadRecord?.env ?? {};
const secretRef = DEV_DB_ENV_CONTRACT.secretRefs[0];
const expectedSecretRef = dbSecretRefPlaceholder();
const expectedSslMode = DEV_DB_ENV_CONTRACT.nonSecretDefaults.HWLAB_CLOUD_DB_SSL_MODE;
const deploySecretMatches = deployEnv.HWLAB_CLOUD_DB_URL === expectedSecretRef;
const workloadSecretMatches = secretRefMatches(workloadEnv.HWLAB_CLOUD_DB_URL, secretRef);
const deploySslMatches = deployEnv.HWLAB_CLOUD_DB_SSL_MODE === expectedSslMode;
const workloadSslMatches = workloadEnv.HWLAB_CLOUD_DB_SSL_MODE === expectedSslMode;
const ready = deploySecretMatches && workloadSecretMatches && deploySslMatches && workloadSslMatches;
if (!ready) {
addDiagnostic(ctx, {
code: "cloud_api_db_contract_mismatch",
path: "deploy.cloudApiDb",
message: "hwlab-cloud-api desired state must preserve DEV DB Secret ref and non-SSL runtime mode",
expected: {
secretRef: `${secretRef.secretName}/${secretRef.secretKey}`,
sslMode: expectedSslMode
},
actual: {
deploySecretRef: deploySecretMatches ? "secretRef:declared" : "missing_or_mismatched",
workloadSecretRef: workloadSecretMatches ? "secretRef:declared" : "missing_or_mismatched",
deploySslMode: deployEnv.HWLAB_CLOUD_DB_SSL_MODE ?? null,
workloadSslMode: workloadEnv.HWLAB_CLOUD_DB_SSL_MODE ?? null
},
secretMaterialRead: false,
valuesRedacted: true
});
}
recordObservation(ctx, {
source: "deploy",
serviceId: "hwlab-cloud-api",
path: `${deployPath}.services.hwlab-cloud-api.env.HWLAB_CLOUD_DB_SSL_MODE`,
field: "HWLAB_CLOUD_DB_SSL_MODE",
kind: "runtime-config",
value: deployEnv.HWLAB_CLOUD_DB_SSL_MODE ?? null,
expected: expectedSslMode
});
recordObservation(ctx, {
source: "workload",
serviceId: "hwlab-cloud-api",
path: `${workloadsPath}.hwlab-cloud-api.env.HWLAB_CLOUD_DB_SSL_MODE`,
field: "HWLAB_CLOUD_DB_SSL_MODE",
kind: "runtime-config",
value: workloadEnv.HWLAB_CLOUD_DB_SSL_MODE ?? null,
expected: expectedSslMode
});
return {
contractVersion: DEV_DB_ENV_CONTRACT.contractVersion,
environment: DEV_DB_ENV_CONTRACT.environment,
status: ready ? "pass" : "blocked",
ready,
secretRef: {
env: secretRef.env,
secretName: secretRef.secretName,
secretKey: secretRef.secretKey,
deployPlaceholderPresent: deploySecretMatches,
workloadSecretRefPresent: workloadSecretMatches,
present: deploySecretMatches && workloadSecretMatches,
redacted: true
},
sslMode: {
env: "HWLAB_CLOUD_DB_SSL_MODE",
value: deployEnv.HWLAB_CLOUD_DB_SSL_MODE ?? null,
workloadValue: workloadEnv.HWLAB_CLOUD_DB_SSL_MODE ?? null,
expected: expectedSslMode,
deployMatches: deploySslMatches,
workloadMatches: workloadSslMatches,
secret: false
},
secretMaterialRead: false,
valuesRedacted: true,
liveDbEvidence: false,
fixtureEvidence: false
};
}
function indexWorkloads(workloads) {
const byService = new Map();
for (const item of listItems(workloads)) {
@@ -616,6 +711,7 @@ export async function buildDesiredStatePlan(options = {}) {
const services = [];
let codeAgentProvider = null;
let cloudApiDb = null;
for (const serviceId of serviceIds) {
const deployService = deployByService.get(serviceId);
const catalogService = catalogByService.get(serviceId);
@@ -774,6 +870,7 @@ export async function buildDesiredStatePlan(options = {}) {
services.push(service);
if (serviceId === "hwlab-cloud-api") {
cloudApiDb = inspectCloudApiDbDesiredState(ctx, deployService, workloadsForService);
codeAgentProvider = inspectCodeAgentProviderDesiredState(ctx, deployService, workloadsForService);
}
}
@@ -838,6 +935,13 @@ export async function buildDesiredStatePlan(options = {}) {
nonAuthoritativeEvidence: [artifactReportPath],
note: "This planner reviews source desired-state only. It does not prove image existence, registry reachability, a real DEV apply, or M3 DEV-LIVE hardware-loop evidence."
},
cloudApiDb: cloudApiDb ?? {
status: "blocked",
ready: false,
secretMaterialRead: false,
valuesRedacted: true,
liveDbEvidence: false
},
codeAgentProvider: codeAgentProvider ?? {
status: "blocked",
ready: false,
+23 -2
View File
@@ -1133,14 +1133,33 @@ async function checkCloudApiDb(deploy, workloads, services, blockers) {
const missingSecretRefs = requiredEnv
.filter((env) => env.secretRef && !env.secretRef.present)
.map((env) => `${env.secretRef.secretName}/${env.secretRef.secretKey}`);
const expectedSslMode = DEV_DB_ENV_CONTRACT.nonSecretDefaults.HWLAB_CLOUD_DB_SSL_MODE;
const sslModeMatches =
deployEnv.HWLAB_CLOUD_DB_SSL_MODE === expectedSslMode &&
workloadEnv.get("HWLAB_CLOUD_DB_SSL_MODE")?.value === expectedSslMode;
const mismatchedNonSecretEnv = sslModeMatches
? []
: [`HWLAB_CLOUD_DB_SSL_MODE must be ${expectedSslMode}`];
const dnsContract = inspectCloudApiDbOptionalAliasContract(deployEnv, workloadEnv, services);
const missingDnsContract = dnsContract.missing;
if (missingManifest.length > 0 || missingK8s.length > 0 || missingSecretRefs.length > 0 || missingDnsContract.length > 0) {
if (
missingManifest.length > 0 ||
missingK8s.length > 0 ||
missingSecretRefs.length > 0 ||
mismatchedNonSecretEnv.length > 0 ||
missingDnsContract.length > 0
) {
addBlocker(
blockers,
"runtime_blocker",
"cloud-api-db-config",
`cloud-api DEV DB env/authority contract is incomplete; missing ${[...missingManifest, ...missingK8s, ...missingSecretRefs, ...missingDnsContract].join(", ")}`
`cloud-api DEV DB env/authority contract is incomplete; missing ${[
...missingManifest,
...missingK8s,
...missingSecretRefs,
...mismatchedNonSecretEnv,
...missingDnsContract
].join(", ")}`
);
}
@@ -1148,6 +1167,7 @@ async function checkCloudApiDb(deploy, workloads, services, blockers) {
missingManifest.length === 0 &&
missingK8s.length === 0 &&
missingSecretRefs.length === 0 &&
mismatchedNonSecretEnv.length === 0 &&
missingDnsContract.length === 0;
const health = {
status: configReady ? "degraded" : "blocked",
@@ -1181,6 +1201,7 @@ async function checkCloudApiDb(deploy, workloads, services, blockers) {
missingManifest,
missingK8s,
missingSecretRefs,
mismatchedNonSecretEnv,
missingDnsContract,
dns: dnsContract,
runtimeHealth: summarizeDbContract(health),
+14 -4
View File
@@ -834,20 +834,21 @@ function validateCloudApiDbContract(reporter, deploy, workloads, services) {
...staticContract.missingDeployEnv,
...staticContract.missingK8sEnv,
...staticContract.missingSecretRefs,
...staticContract.mismatchedNonSecretEnv,
...staticContract.missingDnsContract
];
reporter.check(
"cloud-api-db-env-contract",
"db",
"blocked",
`cloud-api DEV DB manifest is missing ${missing.join(", ")}.`,
`cloud-api DEV DB manifest contract is blocked by ${missing.join(", ")}.`,
evidence
);
reporter.block({
type: "contract_blocker",
scope: "cloud-api-db-env-contract",
summary: `cloud-api DEV DB contract is incomplete; missing ${missing.join(", ")}.`,
nextTask: "Repair deploy/deploy.json and deploy/k8s/base/workloads.yaml so they expose the required DB env names and redacted Secret reference. Do not make cloud-api-db a hard readiness gate unless this repo also owns its Service/Endpoint rollout contract."
summary: `cloud-api DEV DB contract is incomplete; blocked by ${missing.join(", ")}.`,
nextTask: "Repair deploy/deploy.json and deploy/k8s/base/workloads.yaml so they expose the required DB env names, redacted Secret reference, and HWLAB_CLOUD_DB_SSL_MODE=disable. Do not make cloud-api-db a hard readiness gate unless this repo also owns its Service/Endpoint rollout contract."
});
}
@@ -873,7 +874,7 @@ function validateCloudApiDbContract(reporter, deploy, workloads, services) {
type: "runtime_blocker",
scope: "cloud-api-db-health-gate",
summary: `cloud-api DB runtime env is not ready; missing ${healthContract.missingEnv.join(", ")}.`,
nextTask: "Configure DEV hwlab-cloud-api with Secret hwlab-cloud-api-dev-db/database-url and HWLAB_CLOUD_DB_SSL_MODE=require, then rerun health/preflight without printing the secret value."
nextTask: "Configure DEV hwlab-cloud-api with Secret hwlab-cloud-api-dev-db/database-url and HWLAB_CLOUD_DB_SSL_MODE=disable, then rerun health/preflight without printing the secret value."
});
}
@@ -914,6 +915,13 @@ function inspectCloudApiDbStaticContract(deploy, workloads, services) {
const missingSecretRefs = fields
.filter((field) => field.secretRef && !field.secretRef.present)
.map((field) => `${field.secretRef.secretName}/${field.secretRef.secretKey}`);
const expectedSslMode = DEV_DB_ENV_CONTRACT.nonSecretDefaults.HWLAB_CLOUD_DB_SSL_MODE;
const sslModeMatches =
deployEnv.HWLAB_CLOUD_DB_SSL_MODE === expectedSslMode &&
workloadEnv.get("HWLAB_CLOUD_DB_SSL_MODE")?.value === expectedSslMode;
const mismatchedNonSecretEnv = sslModeMatches
? []
: [`HWLAB_CLOUD_DB_SSL_MODE must be ${expectedSslMode}`];
const dnsContract = inspectCloudApiDbOptionalAliasContract(deployEnv, workloadEnv, services);
return {
@@ -923,12 +931,14 @@ function inspectCloudApiDbStaticContract(deploy, workloads, services) {
missingDeployEnv.length === 0 &&
missingK8sEnv.length === 0 &&
missingSecretRefs.length === 0 &&
mismatchedNonSecretEnv.length === 0 &&
dnsContract.ready,
requiredEnv: fields,
dns: dnsContract,
missingDeployEnv,
missingK8sEnv,
missingSecretRefs,
mismatchedNonSecretEnv,
missingDnsContract: dnsContract.missing,
secretMaterialRead: false,
valuesRedacted: true,
+6 -6
View File
@@ -15,7 +15,7 @@ test("source check is non-secret and does not attempt live DB access", async ()
const report = await buildDevRuntimeMigrationReport(parseArgs(["--check"]), {
env: {
HWLAB_CLOUD_DB_URL: "postgresql://hwlab:secret-password@db.example.test:5432/hwlab",
HWLAB_CLOUD_DB_SSL_MODE: "require"
HWLAB_CLOUD_DB_SSL_MODE: "disable"
},
now: () => "2026-05-22T00:00:00.000Z"
});
@@ -38,7 +38,7 @@ test("apply mode refuses missing DEV confirmation before touching query client",
const report = await buildDevRuntimeMigrationReport(parseArgs(["--apply"]), {
env: {
HWLAB_CLOUD_DB_URL: "postgresql://hwlab:redacted@example.invalid:5432/hwlab",
HWLAB_CLOUD_DB_SSL_MODE: "require"
HWLAB_CLOUD_DB_SSL_MODE: "disable"
},
queryClient,
now: () => "2026-05-22T00:00:00.000Z"
@@ -56,7 +56,7 @@ test("live dry-run separates migration ledger blocker from auth and schema", asy
{
env: {
HWLAB_CLOUD_DB_URL: "postgresql://hwlab:redacted@example.invalid:5432/hwlab",
HWLAB_CLOUD_DB_SSL_MODE: "require"
HWLAB_CLOUD_DB_SSL_MODE: "disable"
},
queryClient: createFakeQueryClient({ migrationReady: false }),
now: () => "2026-05-22T00:00:00.000Z"
@@ -81,7 +81,7 @@ test("apply mode records ledger and verifies durable runtime readiness", async (
{
env: {
HWLAB_CLOUD_DB_URL: "postgresql://hwlab:redacted@example.invalid:5432/hwlab",
HWLAB_CLOUD_DB_SSL_MODE: "require"
HWLAB_CLOUD_DB_SSL_MODE: "disable"
},
queryClient,
now: () => "2026-05-22T00:00:00.000Z"
@@ -112,7 +112,7 @@ test("live dry-run closes pg pool after readiness verification", async () => {
{
env: {
HWLAB_CLOUD_DB_URL: "postgresql://hwlab:redacted@example.invalid:5432/hwlab",
HWLAB_CLOUD_DB_SSL_MODE: "require"
HWLAB_CLOUD_DB_SSL_MODE: "disable"
},
pgModuleLoader: async () => createFakePgModule({ backingClient, pools }),
now: () => "2026-05-22T00:00:00.000Z"
@@ -133,7 +133,7 @@ test("apply mode uses a dedicated pg client transaction", async () => {
{
env: {
HWLAB_CLOUD_DB_URL: "postgresql://hwlab:redacted@example.invalid:5432/hwlab",
HWLAB_CLOUD_DB_SSL_MODE: "require"
HWLAB_CLOUD_DB_SSL_MODE: "disable"
},
pgModuleLoader: async () => createFakePgModule({ backingClient, pools }),
now: () => "2026-05-22T00:00:00.000Z"
+10 -1
View File
@@ -170,10 +170,19 @@ assert.equal(cloudApi.env.HWLAB_COMMIT_ID, deployManifest.commitId, "cloud-api h
assert.equal(cloudApi.env.HWLAB_IMAGE, cloudApi.image, "cloud-api health image evidence");
assert.equal(cloudApi.env.HWLAB_IMAGE_TAG, deployManifest.commitId.slice(0, 7), "cloud-api health image tag evidence");
assert.equal(cloudApi.env.HWLAB_CLOUD_DB_URL, "secretRef:hwlab-cloud-api-dev-db/database-url", "cloud-api DB URL must be a Secret reference placeholder");
assert.equal(cloudApi.env.HWLAB_CLOUD_DB_SSL_MODE, "require", "cloud-api DB SSL mode");
assert.equal(
cloudApi.env.HWLAB_CLOUD_DB_SSL_MODE,
DEV_DB_ENV_CONTRACT.nonSecretDefaults.HWLAB_CLOUD_DB_SSL_MODE,
"cloud-api DEV DB SSL mode"
);
assert.equal(cloudApi.env.HWLAB_CLOUD_DB_CONTRACT, "dev-redacted-presence-only", "cloud-api DB contract marker");
assert.equal(cloudApi.env.HWLAB_CLOUD_RUNTIME_ADAPTER, "postgres", "cloud-api runtime durable adapter");
assert.equal(cloudApi.env.HWLAB_CLOUD_RUNTIME_DURABLE, "true", "cloud-api runtime durable flag");
assert.equal(
cloudApiWorkloadEnv.HWLAB_CLOUD_DB_SSL_MODE?.value,
DEV_DB_ENV_CONTRACT.nonSecretDefaults.HWLAB_CLOUD_DB_SSL_MODE,
"cloud-api workload DEV DB SSL mode"
);
assert.equal(cloudApiWorkloadEnv.HWLAB_CLOUD_RUNTIME_ADAPTER?.value, "postgres", "cloud-api workload runtime durable adapter");
assert.equal(cloudApiWorkloadEnv.HWLAB_CLOUD_RUNTIME_DURABLE?.value, "true", "cloud-api workload runtime durable flag");
assert.equal(cloudApi.env.HWLAB_CLOUD_DB_SERVICE_NAME, undefined, "cloud-api DB alias service name is optional");