fix: preserve secret-url DB readiness authority

This commit is contained in:
Code Queue Review
2026-05-22 23:19:13 +00:00
parent ca1cde56e5
commit 332f50493c
24 changed files with 442 additions and 286 deletions
+4 -3
View File
@@ -18,9 +18,10 @@ 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`. It also declares the non-secret DB DNS
contract `cloud-api-db.hwlab-dev.svc.cluster.local:5432`, backed by
selectorless `Service/cloud-api-db` in `hwlab-dev`; see
`HWLAB_CLOUD_DB_SSL_MODE=require`. 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
[docs/reference/dev-runtime-boundary.md](../docs/reference/dev-runtime-boundary.md).
The repository records names only, never secret values or a live DB
connection string; runtime health reports redacted env injection and DB
-4
View File
@@ -196,10 +196,6 @@
"HWLAB_CLOUD_DB_URL": "secretRef:hwlab-cloud-api-dev-db/database-url",
"HWLAB_CLOUD_DB_SSL_MODE": "require",
"HWLAB_CLOUD_DB_CONTRACT": "dev-redacted-presence-only",
"HWLAB_CLOUD_DB_SERVICE_NAME": "cloud-api-db",
"HWLAB_CLOUD_DB_SERVICE_NAMESPACE": "hwlab-dev",
"HWLAB_CLOUD_DB_HOST": "cloud-api-db.hwlab-dev.svc.cluster.local",
"HWLAB_CLOUD_DB_PORT": "5432",
"HWLAB_CLOUD_RUNTIME_ADAPTER": "postgres",
"HWLAB_CLOUD_RUNTIME_DURABLE": "true",
"HWLAB_CODE_AGENT_PROVIDER": "openai",
-16
View File
@@ -371,22 +371,6 @@
"type": "string",
"const": "dev-redacted-presence-only"
},
"HWLAB_CLOUD_DB_SERVICE_NAME": {
"type": "string",
"const": "cloud-api-db"
},
"HWLAB_CLOUD_DB_SERVICE_NAMESPACE": {
"type": "string",
"const": "hwlab-dev"
},
"HWLAB_CLOUD_DB_HOST": {
"type": "string",
"const": "cloud-api-db.hwlab-dev.svc.cluster.local"
},
"HWLAB_CLOUD_DB_PORT": {
"type": "string",
"const": "5432"
},
"HWLAB_CLOUD_RUNTIME_ADAPTER": {
"type": "string",
"const": "postgres"
-23
View File
@@ -27,29 +27,6 @@
]
}
},
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"name": "cloud-api-db",
"namespace": "hwlab-dev",
"labels": {
"app.kubernetes.io/name": "cloud-api-db",
"hwlab.pikastech.local/component": "cloud-api-db",
"hwlab.pikastech.local/source-contract": "db-dns"
}
},
"spec": {
"type": "ClusterIP",
"ports": [
{
"name": "postgres",
"port": 5432,
"targetPort": "postgres"
}
]
}
},
{
"apiVersion": "v1",
"kind": "Service",
-16
View File
@@ -81,22 +81,6 @@
"name": "HWLAB_CLOUD_DB_CONTRACT",
"value": "dev-redacted-presence-only"
},
{
"name": "HWLAB_CLOUD_DB_SERVICE_NAME",
"value": "cloud-api-db"
},
{
"name": "HWLAB_CLOUD_DB_SERVICE_NAMESPACE",
"value": "hwlab-dev"
},
{
"name": "HWLAB_CLOUD_DB_HOST",
"value": "cloud-api-db.hwlab-dev.svc.cluster.local"
},
{
"name": "HWLAB_CLOUD_DB_PORT",
"value": "5432"
},
{
"name": "HWLAB_CLOUD_RUNTIME_ADAPTER",
"value": "postgres"
+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, HWLAB_CLOUD_DB_SSL_MODE=require, and stable internal DNS cloud-api-db.hwlab-dev.svc.cluster.local:5432 backed by Service cloud-api-db in hwlab-dev; 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=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-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",
+10 -4
View File
@@ -61,14 +61,20 @@ If both env vars are present, cloud-api attempts a short read-only TCP
connection to the DB endpoint from the injected runtime env. The health payload
keeps all endpoint details redacted and reports only:
The source-controlled DEV DNS contract for that endpoint is
`cloud-api-db.hwlab-dev.svc.cluster.local:5432`. The actual connection string
still comes from `hwlab-cloud-api-dev-db/database-url`; source records only the
non-secret host/service/namespace/port contract.
The runtime DB readiness authority is the host parsed from the injected
`HWLAB_CLOUD_DB_URL` Secret value. Health reports this as
`db.endpointSource: "secret-url-host"` without printing the host, username,
password, or full URL. The `cloud-api-db` name is only an optional future alias;
it is not the TCP probe target and a missing alias must not reverse-fail live DB
success from the Secret URL host.
`.invalid` hosts, including `hwlab-dev-db.invalid`, are forbidden as DEV
runtime targets and may be used only as negative fixtures.
- `db.configReady`: required env names are present.
- `db.endpointSource`: `secret-url-host`, the authoritative redacted TCP dial
target parsed from `HWLAB_CLOUD_DB_URL`.
- `db.optionalPublicDnsAlias`: diagnostic metadata for the non-authoritative
`cloud-api-db` alias; `requiredForReadiness` and `usedForProbe` stay false.
- `db.connectionAttempted`: the runtime tried the live connection path.
- `db.connectionResult`: redacted classifier such as `connected`, `refused`,
`timeout`, `dns_error`, `invalid_url`, or `unsupported_protocol`.
+5 -4
View File
@@ -228,10 +228,11 @@ 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`. The non-secret DB DNS contract is
`cloud-api-db.hwlab-dev.svc.cluster.local:5432` via selectorless
`Service/cloud-api-db` in `hwlab-dev`. The local health gate reports DB
runtime config without printing the connection string.
`HWLAB_CLOUD_DB_SSL_MODE=require`. 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
config without printing the connection string.
No PROD resource, secret value, UniDesk runtime substitute, browser e2e,
heavyweight e2e, or force push is part of this flow.
+13 -6
View File
@@ -26,17 +26,23 @@ forwarding checks.
`db` in the cloud-api health payload is a redacted configuration gate. It
reports required env names, presence, missing names, and Secret reference names
only. Runtime health additionally reports redacted DB readiness layers:
`configReady`, `envInjected`, `connectionAttempted`, `connectionResult`, and
`liveConnected`. It must not expose a connection string, token, password, DB
host, username, or claim fixture output as live DB evidence.
`configReady`, `envInjected`, `endpointSource`, `connectionAttempted`,
`connectionResult`, and `liveConnected`. It must not expose a connection
string, token, password, DB host, username, or claim fixture output as live DB
evidence.
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`.
- Stable k3s DB DNS: `cloud-api-db.hwlab-dev.svc.cluster.local:5432`,
backed by selectorless `Service/cloud-api-db` in `hwlab-dev`.
- Runtime TCP dial target: the redacted host parsed from
`HWLAB_CLOUD_DB_URL`, reported as `endpointSource="secret-url-host"`.
`cloud-api-db` is only an optional desired alias. Until this repo owns the
Service plus Endpoint or EndpointSlice manifests and rollout/apply contract, it
is not a readiness authority, is not the TCP probe target, and a missing alias
must not reverse-fail live DB success from the Secret URL host.
When the Secret/env is absent, the health JSON should keep
`db.connected: false`, set `db.status: "blocked"`, and list the missing env
@@ -46,7 +52,8 @@ present but no live DB probe is attempted, the gate remains blocked with
`liveConnected` is false, the gate remains blocked/degraded with the redacted
connection classifier. `connectionResult: "dns_error"` with
`classification: "dns_resolution_failed"` means DB endpoint DNS failed from the
cloud-api runtime. Env presence alone is not live DB evidence.
cloud-api runtime for the Secret URL host. Env presence alone is not live DB
evidence.
The Code Agent provider Secret for #143 is a separate blocker. The edge-health
report may record only key-presence evidence for
+5 -3
View File
@@ -67,9 +67,10 @@ 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`. The non-secret DB DNS contract is
`cloud-api-db.hwlab-dev.svc.cluster.local:5432` via selectorless
`Service/cloud-api-db` in `hwlab-dev`.
`HWLAB_CLOUD_DB_SSL_MODE=require`. 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.
- The local cloud-api health payload reports DB env presence/missing status with
redacted values only. This is a readiness gate, not live DB evidence.
- `deploy/frp` and `deploy/master-edge` describe the D601-to-master DEV route
@@ -114,6 +115,7 @@ rerunning the preflight.
The DB gate has two common blocked scopes:
- `cloud-api-db-env-contract`: manifest/Kubernetes placeholders are incomplete.
The optional `cloud-api-db` alias is not part of this readiness gate.
- `cloud-api-db-health-gate`: runtime env presence is missing. The next task is
to configure the DEV Secret/env names, not to print or commit any secret
value.
+1 -1
View File
@@ -19,7 +19,7 @@
| 用户反馈分流规则 | [user-feedback-triage.md](user-feedback-triage.md) |
| 文档治理与 docs-spec 入库规则 | [documentation-governance.md](documentation-governance.md) |
| 架构和 M3 上位约束 | [architecture.md](architecture.md) |
| DEV 运行态、端口、k3s、DB DNS 和环境边界 | [dev-runtime-boundary.md](dev-runtime-boundary.md) |
| DEV 运行态、端口、k3s、DB readiness 和环境边界 | [dev-runtime-boundary.md](dev-runtime-boundary.md) |
| 部署正规化、artifact 发布、回滚和 Cloud Web rollout | [deployment-publish.md](deployment-publish.md) |
| Cloud Workbench 默认界面和 UX 边界 | [cloud-workbench.md](cloud-workbench.md) |
| Code Agent chat 同源通道 readiness 与真实回复判定 | [code-agent-chat-readiness.md](code-agent-chat-readiness.md) |
+28 -14
View File
@@ -54,35 +54,49 @@ node scripts/d601-k3s-readonly-observability.mjs
The preflight must not print secret values, kubeconfig material, ConfigMap
values, or token content.
## Cloud API DB DNS Contract
## Cloud API DB Readiness Authority
`hwlab-cloud-api` reads the DEV database connection string from Secret
reference `hwlab-cloud-api-dev-db/database-url`. The Secret value is not stored
in source, not printed by reports, and not required for offline validation.
The non-secret DNS contract is source-controlled:
Runtime DB readiness uses the redacted host parsed from the injected
`HWLAB_CLOUD_DB_URL` Secret value:
| Field | Value |
| --- | --- |
| Authority source | `secret-url-host` |
| Authority env | `HWLAB_CLOUD_DB_URL` |
| Required for readiness | `true` |
| Probe target | redacted host and port parsed from the Secret URL |
Health output may report `endpointSource: secret-url-host`, DNS/TCP result,
`liveConnected`, and `liveDbEvidence`, but must keep the DB endpoint and Secret
value redacted.
The non-secret `cloud-api-db` name is an optional desired alias:
| Field | Value |
| --- | --- |
| Source | `optional-public-dns-alias` |
| Service | `cloud-api-db` |
| Namespace | `hwlab-dev` |
| Host | `cloud-api-db.hwlab-dev.svc.cluster.local` |
| Port | `5432` |
| Port name | `postgres` |
| Required for readiness | `false` |
| Used for probe | `false` |
`deploy/k8s/base/services.yaml` must include a selectorless
`Service/cloud-api-db` with that port so k3s DNS has a stable handle before the
actual DB endpoints are provisioned. A selectorless Service proves only that
the name can exist in cluster DNS; it does not prove a DB endpoint, credential,
TCP connection, schema migration, durable persistence, or M4/M5 readiness.
Missing `Service/cloud-api-db`, Endpoint, EndpointSlice, or alias env vars must
not reverse-fail live DB success from the Secret URL host. A future PR may make
that alias operational only if it also owns the Service plus Endpoint or
EndpointSlice manifests and the rollout/apply contract.
`deploy/deploy.json`, `deploy/k8s/base/workloads.yaml`, and
`internal/cloud/db-contract.mjs` must agree on
`HWLAB_CLOUD_DB_SERVICE_NAME`, `HWLAB_CLOUD_DB_SERVICE_NAMESPACE`,
`HWLAB_CLOUD_DB_HOST`, and `HWLAB_CLOUD_DB_PORT`. `npm run validate` checks
this agreement offline. A live pass still requires `/health/live` to report
`db.ready=true`, `db.connected=true`, and `liveDbEvidence=true` with secret
values redacted.
Source validation checks `HWLAB_CLOUD_DB_URL`, `HWLAB_CLOUD_DB_SSL_MODE`,
`endpointSource=secret-url-host`, and `liveDbEvidence=true` with secret values
redacted. It must not require `HWLAB_CLOUD_DB_SERVICE_NAME`,
`HWLAB_CLOUD_DB_SERVICE_NAMESPACE`, `HWLAB_CLOUD_DB_HOST`, or
`HWLAB_CLOUD_DB_PORT` as current readiness inputs.
The DB readiness contract is layered:
+83 -8
View File
@@ -16,12 +16,22 @@ export const DEV_DB_ENV_CONTRACT = Object.freeze({
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"
portName: "postgres",
requiredForReadiness: false,
usedForProbe: false
}),
readinessLayers: Object.freeze([
"dns",
@@ -30,11 +40,7 @@ export const DEV_DB_ENV_CONTRACT = Object.freeze({
"schema"
]),
nonSecretDefaults: Object.freeze({
HWLAB_CLOUD_DB_SSL_MODE: "require",
HWLAB_CLOUD_DB_SERVICE_NAME: "cloud-api-db",
HWLAB_CLOUD_DB_SERVICE_NAMESPACE: "hwlab-dev",
HWLAB_CLOUD_DB_HOST: "cloud-api-db.hwlab-dev.svc.cluster.local",
HWLAB_CLOUD_DB_PORT: "5432"
HWLAB_CLOUD_DB_SSL_MODE: "require"
}),
forbidden: Object.freeze({
prodAllowed: false,
@@ -68,6 +74,7 @@ export function buildDbHealthContract(env = process.env) {
const connected = false;
const connectionChecked = false;
const status = configReady ? "degraded" : "blocked";
const endpoint = buildEndpointDiagnostics(env);
return {
contractVersion: DEV_DB_ENV_CONTRACT.contractVersion,
@@ -84,6 +91,9 @@ export function buildDbHealthContract(env = process.env) {
mode: configReady ? "configured_without_live_connection_attempt" : "not_configured",
fields,
missingEnv,
endpoint,
endpointSource: endpoint.authoritative.source,
optionalPublicDnsAlias: endpoint.optionalPublicDnsAlias,
secretRefs: DEV_DB_ENV_CONTRACT.secretRefs.map(({ env: envName, secretName, secretKey }) => ({
env: envName,
secretName,
@@ -134,6 +144,7 @@ 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],
@@ -184,6 +195,8 @@ export function summarizeDbContract(db = buildDbHealthContract()) {
redacted
})
),
endpointSource: db.endpointSource ?? db.endpoint?.authoritative?.source ?? db.connection?.endpointSource ?? DEV_DB_ENV_CONTRACT.endpointAuthority.source,
optionalPublicDnsAlias: summarizeOptionalPublicDnsAlias(db.optionalPublicDnsAlias ?? db.endpoint?.optionalPublicDnsAlias),
connection: summarizeConnection(db.connection),
redaction: summarizeRedaction(db.redaction),
readinessLayers: buildReadinessLayers(db.connection),
@@ -206,6 +219,7 @@ function buildNotAttemptedConnection(configReady, missingEnv) {
networkAttempted: false,
result: configReady ? "not_attempted" : "not_attempted_missing_env",
classification: configReady ? "configured_no_live_attempt" : "missing_runtime_env",
endpointSource: DEV_DB_ENV_CONTRACT.endpointAuthority.source,
probeType: "tcp-connect",
endpointRedacted: true,
valueRedacted: true,
@@ -235,6 +249,7 @@ async function probeDbConnection(env, options) {
networkAttempted: false,
result: parsed.result,
classification: parsed.classification,
endpointSource: DEV_DB_ENV_CONTRACT.endpointAuthority.source,
probeType: "tcp-connect",
endpointRedacted: true,
valueRedacted: true,
@@ -248,7 +263,8 @@ async function probeDbConnection(env, options) {
return tcpConnect({
host: parsed.host,
port: parsed.port,
timeoutMs
timeoutMs,
endpointSource: DEV_DB_ENV_CONTRACT.endpointAuthority.source
});
}
@@ -303,7 +319,7 @@ export function parseDbUrlContract(rawUrl) {
}
}
function tcpConnect({ host, port, timeoutMs }) {
function tcpConnect({ host, port, timeoutMs, endpointSource }) {
return new Promise((resolve) => {
const startedAt = Date.now();
const socket = net.connect({ host, port, timeout: timeoutMs });
@@ -316,6 +332,7 @@ function tcpConnect({ host, port, timeoutMs }) {
resolve({
attempted: true,
networkAttempted: true,
endpointSource,
probeType: "tcp-connect",
endpointRedacted: true,
valueRedacted: true,
@@ -397,6 +414,9 @@ function applyConnectionResult(base, connection) {
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,
@@ -493,6 +513,7 @@ function summarizeConnection(connection) {
networkAttempted: Boolean(connection.networkAttempted),
result: connection.result,
classification: connection.classification,
endpointSource: connection.endpointSource ?? DEV_DB_ENV_CONTRACT.endpointAuthority.source,
probeType: connection.probeType,
endpointRedacted: true,
valueRedacted: true,
@@ -502,6 +523,60 @@ function summarizeConnection(connection) {
};
}
function buildEndpointDiagnostics(env) {
const authority = DEV_DB_ENV_CONTRACT.endpointAuthority;
return {
authoritative: {
source: authority.source,
env: authority.env,
requiredForReadiness: authority.requiredForReadiness,
usedForProbe: true,
endpointRedacted: true,
valueRedacted: true
},
optionalPublicDnsAlias: buildOptionalPublicDnsAlias(env)
};
}
function buildOptionalPublicDnsAlias(env) {
const alias = DEV_DB_ENV_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) {
const fallback = buildOptionalPublicDnsAlias({});
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,
+4
View File
@@ -64,6 +64,10 @@ test("system.health includes the redacted DEV DB env contract", async () => {
assert.equal(response.result.db.liveDbEvidence, false);
assert.equal(response.result.db.connectionAttempted, false);
assert.equal(response.result.db.connectionResult, "not_attempted_missing_env");
assert.equal(response.result.db.endpointSource, "secret-url-host");
assert.equal(response.result.db.optionalPublicDnsAlias.source, "optional-public-dns-alias");
assert.equal(response.result.db.optionalPublicDnsAlias.requiredForReadiness, false);
assert.equal(response.result.db.optionalPublicDnsAlias.usedForProbe, false);
assert.equal(response.result.db.redaction.valuesRedacted, true);
assert.equal(response.result.db.redaction.secretMaterialRead, false);
assert.equal(response.result.db.safety.liveDbEvidence, false);
+35
View File
@@ -38,6 +38,13 @@ test("cloud api exposes /health, /health/live, and /live probes", async () => {
assert.equal(healthPayload.db.liveDbEvidence, false);
assert.equal(healthPayload.db.connectionAttempted, false);
assert.equal(healthPayload.db.connectionResult, "not_attempted_missing_env");
assert.equal(healthPayload.db.endpointSource, "secret-url-host");
assert.equal(healthPayload.db.endpoint.authoritative.source, "secret-url-host");
assert.equal(healthPayload.db.endpoint.authoritative.env, "HWLAB_CLOUD_DB_URL");
assert.equal(healthPayload.db.endpoint.authoritative.usedForProbe, true);
assert.equal(healthPayload.db.optionalPublicDnsAlias.source, "optional-public-dns-alias");
assert.equal(healthPayload.db.optionalPublicDnsAlias.requiredForReadiness, false);
assert.equal(healthPayload.db.optionalPublicDnsAlias.usedForProbe, false);
assert.equal(healthPayload.db.redaction.valuesRedacted, true);
assert.equal(healthPayload.db.redaction.secretMaterialRead, false);
assert.equal(healthPayload.db.safety.liveDbEvidence, false);
@@ -94,11 +101,21 @@ test("cloud api exposes /health, /health/live, and /live probes", async () => {
test("cloud api health reports DB env presence and live connection classification without leaking values", async () => {
const originalUrl = process.env.HWLAB_CLOUD_DB_URL;
const originalSslMode = process.env.HWLAB_CLOUD_DB_SSL_MODE;
const originalAliasEnv = {
HWLAB_CLOUD_DB_SERVICE_NAME: process.env.HWLAB_CLOUD_DB_SERVICE_NAME,
HWLAB_CLOUD_DB_SERVICE_NAMESPACE: process.env.HWLAB_CLOUD_DB_SERVICE_NAMESPACE,
HWLAB_CLOUD_DB_HOST: process.env.HWLAB_CLOUD_DB_HOST,
HWLAB_CLOUD_DB_PORT: process.env.HWLAB_CLOUD_DB_PORT
};
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@127.0.0.1:${dbPort}/hwlab`;
process.env.HWLAB_CLOUD_DB_SSL_MODE = "require";
delete process.env.HWLAB_CLOUD_DB_SERVICE_NAME;
delete process.env.HWLAB_CLOUD_DB_SERVICE_NAMESPACE;
delete process.env.HWLAB_CLOUD_DB_HOST;
delete process.env.HWLAB_CLOUD_DB_PORT;
const server = createCloudApiServer();
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
@@ -115,6 +132,14 @@ test("cloud api health reports DB env presence and live connection classificatio
assert.equal(payload.db.connectionChecked, true);
assert.equal(payload.db.connectionAttempted, true);
assert.equal(payload.db.connectionResult, "connected");
assert.equal(payload.db.endpointSource, "secret-url-host");
assert.equal(payload.db.connection.endpointSource, "secret-url-host");
assert.equal(payload.db.endpoint.authoritative.source, "secret-url-host");
assert.equal(payload.db.endpoint.authoritative.env, "HWLAB_CLOUD_DB_URL");
assert.equal(payload.db.optionalPublicDnsAlias.source, "optional-public-dns-alias");
assert.equal(payload.db.optionalPublicDnsAlias.requiredForReadiness, false);
assert.equal(payload.db.optionalPublicDnsAlias.usedForProbe, false);
assert.equal(payload.db.optionalPublicDnsAlias.envPresent, false);
assert.equal(payload.db.configReady, true);
assert.equal(payload.db.ready, true);
assert.equal(payload.db.evidence, "live_db_tcp_connection_ready");
@@ -131,6 +156,7 @@ test("cloud api health reports DB env presence and live connection classificatio
assert.equal(JSON.stringify(payload.db).includes("password"), false);
assert.equal(JSON.stringify(payload.db).includes("127.0.0.1"), false);
assert.equal(JSON.stringify(payload.db).includes(String(dbPort)), false);
assert.equal(JSON.stringify(payload.db).includes("cloud-api-db.hwlab-dev.svc.cluster.local"), false);
assert.equal(payload.db.fields.find((field) => field.name === "HWLAB_CLOUD_DB_URL").redacted, true);
assert.equal(payload.db.connection.endpointRedacted, true);
} finally {
@@ -144,6 +170,13 @@ test("cloud api health reports DB env presence and live connection classificatio
} else {
process.env.HWLAB_CLOUD_DB_SSL_MODE = originalSslMode;
}
for (const [name, value] of Object.entries(originalAliasEnv)) {
if (value === undefined) {
delete process.env[name];
} else {
process.env[name] = value;
}
}
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
@@ -253,6 +286,8 @@ test("cloud api health does not treat DB env presence-only as live readiness", a
assert.equal(payload.db.connectionAttempted, true);
assert.equal(payload.db.connectionResult, "forbidden_runtime_host");
assert.equal(payload.db.evidence, "live_db_tcp_connection_blocked");
assert.equal(payload.db.endpointSource, "secret-url-host");
assert.equal(payload.db.connection.endpointSource, "secret-url-host");
assert.equal(payload.db.connection.networkAttempted, false);
assert.equal(payload.db.connection.classification, "db_url_forbidden_invalid_host");
assert.equal(payload.db.readinessLayers.dns.status, "not_proven");
+4
View File
@@ -90,6 +90,10 @@ async function run() {
assert.equal(health.body.db.liveDbEvidence, false);
assert.equal(health.body.db.connectionAttempted, false);
assert.equal(health.body.db.connectionResult, "not_attempted_missing_env");
assert.equal(health.body.db.endpointSource, "secret-url-host");
assert.equal(health.body.db.optionalPublicDnsAlias.source, "optional-public-dns-alias");
assert.equal(health.body.db.optionalPublicDnsAlias.requiredForReadiness, false);
assert.equal(health.body.db.optionalPublicDnsAlias.usedForProbe, false);
assert.equal(health.body.db.ready, false);
assert.deepEqual(health.body.db.missingEnv, ["HWLAB_CLOUD_DB_URL", "HWLAB_CLOUD_DB_SSL_MODE"]);
assert.equal(health.body.runtime.adapter, "memory");
+31 -31
View File
@@ -145,7 +145,7 @@ function validateSource(ctx, manifest) {
const tunnelClient = servicesById.get("hwlab-tunnel-client");
const cli = servicesById.get("hwlab-cli");
expectEqual(ctx, cloudApi?.env?.HWLAB_PUBLIC_ENDPOINT, endpoints.api?.url, "$.services.hwlab-cloud-api.env.HWLAB_PUBLIC_ENDPOINT", "cloud API public endpoint env");
validateCloudApiDbDnsSource(ctx, cloudApi?.env ?? {});
validateCloudApiDbSource(ctx, cloudApi?.env ?? {});
validateCloudApiCodeAgentSource(ctx, cloudApi?.env ?? {});
expectEqual(ctx, cli?.env?.HWLAB_CLI_ENDPOINT, endpoints.api?.url, "$.services.hwlab-cli.env.HWLAB_CLI_ENDPOINT", "CLI endpoint env");
expectEqual(ctx, tunnelClient?.env?.HWLAB_FRP_PUBLIC_PORT, String(expectedPorts.api), "$.services.hwlab-tunnel-client.env.HWLAB_FRP_PUBLIC_PORT", "tunnel API public port env");
@@ -189,13 +189,23 @@ function validateSource(ctx, manifest) {
return { manifest, endpoints, servicesById, proxies, serviceMappings, healthPath: manifest.health?.path };
}
function validateCloudApiDbDnsSource(ctx, env) {
const dns = DEV_DB_ENV_CONTRACT.dns;
const expectedHost = `${dns.serviceName}.${dns.namespace}.svc.cluster.local`;
expectEqual(ctx, env.HWLAB_CLOUD_DB_SERVICE_NAME, dns.serviceName, "$.services.hwlab-cloud-api.env.HWLAB_CLOUD_DB_SERVICE_NAME", "cloud API DB service name");
expectEqual(ctx, env.HWLAB_CLOUD_DB_SERVICE_NAMESPACE, dns.namespace, "$.services.hwlab-cloud-api.env.HWLAB_CLOUD_DB_SERVICE_NAMESPACE", "cloud API DB service namespace");
expectEqual(ctx, env.HWLAB_CLOUD_DB_HOST, expectedHost, "$.services.hwlab-cloud-api.env.HWLAB_CLOUD_DB_HOST", "cloud API DB stable DNS host");
expectEqual(ctx, env.HWLAB_CLOUD_DB_PORT, String(dns.port), "$.services.hwlab-cloud-api.env.HWLAB_CLOUD_DB_PORT", "cloud API DB service port");
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_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");
expectEqual(ctx, alias.requiredForReadiness, false, "internal/cloud/db-contract.mjs.dns.requiredForReadiness", "cloud API DB DNS alias readiness requirement");
expectEqual(ctx, alias.usedForProbe, false, "internal/cloud/db-contract.mjs.dns.usedForProbe", "cloud API DB DNS alias probe source");
for (const name of [
"HWLAB_CLOUD_DB_SERVICE_NAME",
"HWLAB_CLOUD_DB_SERVICE_NAMESPACE",
"HWLAB_CLOUD_DB_HOST",
"HWLAB_CLOUD_DB_PORT"
]) {
expectEqual(ctx, env[name], undefined, `$.services.hwlab-cloud-api.env.${name}`, `${name} is optional and not a readiness hard requirement`);
}
}
function validateCloudApiCodeAgentSource(ctx, env) {
@@ -317,7 +327,7 @@ function validateK3sArtifacts(ctx, source, rendered, services, workloads, health
}
}
validateCloudApiDbDnsArtifacts(ctx, services, workloads);
validateCloudApiDbOptionalAliasArtifacts(ctx, services, workloads);
validateCloudApiCodeAgentArtifacts(ctx, workloads);
expectEqual(ctx, healthContract.data?.endpoint, source.endpoints.api?.url, "deploy/k8s/dev/health-contract.yaml.data.endpoint", "health contract endpoint");
@@ -327,30 +337,20 @@ function validateK3sArtifacts(ctx, source, rendered, services, workloads, health
expectEqual(ctx, masterEdge.prodAcceptance, false, "deploy/master-edge/health-contract.json.prodAcceptance", "master edge PROD acceptance");
}
function validateCloudApiDbDnsArtifacts(ctx, services, workloads) {
const dns = DEV_DB_ENV_CONTRACT.dns;
const expectedHost = `${dns.serviceName}.${dns.namespace}.svc.cluster.local`;
const service = listItems(services).find((item) => item?.metadata?.name === dns.serviceName);
expect(ctx, Boolean(service), "missing_rendered_artifact", "deploy/k8s/base/services.yaml.cloud-api-db", "cloud-api DB stable DNS Service exists");
if (service) {
const port = (service.spec?.ports ?? []).find((entry) => entry.name === dns.portName);
expectEqual(ctx, service.metadata?.namespace, dns.namespace, "deploy/k8s/base/services.yaml.cloud-api-db.metadata.namespace", "cloud-api DB Service namespace");
expectEqual(ctx, service.spec?.type, "ClusterIP", "deploy/k8s/base/services.yaml.cloud-api-db.spec.type", "cloud-api DB Service type");
expectEqual(ctx, service.spec?.selector, undefined, "deploy/k8s/base/services.yaml.cloud-api-db.spec.selector", "cloud-api DB Service is selectorless until endpoints are provisioned");
expectEqual(ctx, service.metadata?.labels?.["hwlab.pikastech.local/source-contract"], "db-dns", "deploy/k8s/base/services.yaml.cloud-api-db.metadata.labels.source-contract", "cloud-api DB Service source-contract label");
expect(ctx, Boolean(port), "missing_rendered_artifact", "deploy/k8s/base/services.yaml.cloud-api-db.spec.ports.postgres", "cloud-api DB Service postgres port exists");
if (port) {
expectEqual(ctx, port.port, dns.port, "deploy/k8s/base/services.yaml.cloud-api-db.spec.ports.postgres.port", "cloud-api DB Service port");
expectEqual(ctx, port.targetPort, dns.portName, "deploy/k8s/base/services.yaml.cloud-api-db.spec.ports.postgres.targetPort", "cloud-api DB Service targetPort");
}
}
function validateCloudApiDbOptionalAliasArtifacts(ctx, services, workloads) {
const alias = DEV_DB_ENV_CONTRACT.dns;
const service = listItems(services).find((item) => item?.metadata?.name === alias.serviceName);
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_SERVICE_NAME"), dns.serviceName, "deploy/k8s/base/workloads.yaml.hwlab-cloud-api.env.HWLAB_CLOUD_DB_SERVICE_NAME", "cloud API workload DB service name");
expectEqual(ctx, env.get("HWLAB_CLOUD_DB_SERVICE_NAMESPACE"), dns.namespace, "deploy/k8s/base/workloads.yaml.hwlab-cloud-api.env.HWLAB_CLOUD_DB_SERVICE_NAMESPACE", "cloud API workload DB service namespace");
expectEqual(ctx, env.get("HWLAB_CLOUD_DB_HOST"), expectedHost, "deploy/k8s/base/workloads.yaml.hwlab-cloud-api.env.HWLAB_CLOUD_DB_HOST", "cloud API workload DB host");
expectEqual(ctx, env.get("HWLAB_CLOUD_DB_PORT"), String(dns.port), "deploy/k8s/base/workloads.yaml.hwlab-cloud-api.env.HWLAB_CLOUD_DB_PORT", "cloud API workload DB port");
for (const name of [
"HWLAB_CLOUD_DB_SERVICE_NAME",
"HWLAB_CLOUD_DB_SERVICE_NAMESPACE",
"HWLAB_CLOUD_DB_HOST",
"HWLAB_CLOUD_DB_PORT"
]) {
expectEqual(ctx, env.get(name), undefined, `deploy/k8s/base/workloads.yaml.hwlab-cloud-api.env.${name}`, `${name} is optional and not injected as readiness authority`);
}
}
function validateCloudApiCodeAgentArtifacts(ctx, workloads) {
+22 -41
View File
@@ -502,7 +502,7 @@ function blockerHint(blocker) {
return "Restore the public DEV health path and confirm it identifies HWLAB dev, not a substitute runtime.";
}
if (blocker.scope === "dev-health-db" || blocker.scope === "cloud-api-db" || blocker.scope === "cloud-api-db-config") {
return "Configure and verify the DEV cloud-api DB env and stable DNS readiness through health output, without reading secret values.";
return "Configure and verify the DEV cloud-api DB Secret URL host readiness through health output, without reading secret values.";
}
return blocker.summary;
}
@@ -749,14 +749,14 @@ 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 dnsContract = inspectCloudApiDbDnsContract(deployEnv, workloadEnv, services);
const dnsContract = inspectCloudApiDbOptionalAliasContract(deployEnv, workloadEnv, services);
const missingDnsContract = dnsContract.missing;
if (missingManifest.length > 0 || missingK8s.length > 0 || missingSecretRefs.length > 0 || missingDnsContract.length > 0) {
addBlocker(
blockers,
"runtime_blocker",
"cloud-api-db-config",
`cloud-api DEV DB env/DNS contract is incomplete; missing ${[...missingManifest, ...missingK8s, ...missingSecretRefs, ...missingDnsContract].join(", ")}`
`cloud-api DEV DB env/authority contract is incomplete; missing ${[...missingManifest, ...missingK8s, ...missingSecretRefs, ...missingDnsContract].join(", ")}`
);
}
@@ -804,15 +804,13 @@ async function checkCloudApiDb(deploy, workloads, services, blockers) {
valuesRedacted: true,
liveDbEvidence: false,
fixtureEvidence: false,
note: "This check records DB env, Secret reference, and stable DNS Service presence only. It is not live DB evidence."
note: "This check records DB env, Secret reference, and Secret URL host authority only. Optional cloud-api-db alias presence is diagnostic and is not live DB evidence."
};
}
function inspectCloudApiDbDnsContract(deployEnv, workloadEnv, services) {
const dns = DEV_DB_ENV_CONTRACT.dns;
const expectedHost = `${dns.serviceName}.${dns.namespace}.svc.cluster.local`;
const service = listItems(services).find((item) => item?.metadata?.name === dns.serviceName) ?? null;
const port = service?.spec?.ports?.find((entry) => entry.name === dns.portName) ?? null;
function inspectCloudApiDbOptionalAliasContract(deployEnv, workloadEnv, services) {
const alias = DEV_DB_ENV_CONTRACT.dns;
const service = listItems(services).find((item) => item?.metadata?.name === alias.serviceName) ?? null;
const actual = {
deployServiceName: deployEnv.HWLAB_CLOUD_DB_SERVICE_NAME,
deployServiceNamespace: deployEnv.HWLAB_CLOUD_DB_SERVICE_NAMESPACE,
@@ -822,42 +820,25 @@ function inspectCloudApiDbDnsContract(deployEnv, workloadEnv, services) {
workloadServiceNamespace: workloadEnv.get("HWLAB_CLOUD_DB_SERVICE_NAMESPACE")?.value,
workloadHost: workloadEnv.get("HWLAB_CLOUD_DB_HOST")?.value,
workloadPort: workloadEnv.get("HWLAB_CLOUD_DB_PORT")?.value,
serviceName: service?.metadata?.name,
serviceNamespace: service?.metadata?.namespace,
serviceType: service?.spec?.type,
serviceSelector: service?.spec?.selector ?? null,
portName: port?.name,
port: port?.port,
targetPort: port?.targetPort
serviceName: service?.metadata?.name
};
const checks = [
["deployEnv.HWLAB_CLOUD_DB_SERVICE_NAME", actual.deployServiceName, dns.serviceName],
["deployEnv.HWLAB_CLOUD_DB_SERVICE_NAMESPACE", actual.deployServiceNamespace, dns.namespace],
["deployEnv.HWLAB_CLOUD_DB_HOST", actual.deployHost, expectedHost],
["deployEnv.HWLAB_CLOUD_DB_PORT", actual.deployPort, String(dns.port)],
["workloadEnv.HWLAB_CLOUD_DB_SERVICE_NAME", actual.workloadServiceName, dns.serviceName],
["workloadEnv.HWLAB_CLOUD_DB_SERVICE_NAMESPACE", actual.workloadServiceNamespace, dns.namespace],
["workloadEnv.HWLAB_CLOUD_DB_HOST", actual.workloadHost, expectedHost],
["workloadEnv.HWLAB_CLOUD_DB_PORT", actual.workloadPort, String(dns.port)],
["Service.metadata.name", actual.serviceName, dns.serviceName],
["Service.metadata.namespace", actual.serviceNamespace, dns.namespace],
["Service.spec.type", actual.serviceType, "ClusterIP"],
["Service.spec.selector", actual.serviceSelector, null],
["Service.port.name", actual.portName, dns.portName],
["Service.port.port", actual.port, dns.port],
["Service.port.targetPort", actual.targetPort, dns.portName]
];
const missing = checks
.filter(([, actualValue, expectedValue]) => !Object.is(actualValue, expectedValue))
.map(([name, actualValue, expectedValue]) => `${name} expected ${expectedValue} got ${actualValue ?? "missing"}`);
const missing = [];
for (const [name, value] of Object.entries(actual)) {
if (value !== undefined) {
missing.push(`${name} must be absent because ${alias.serviceName} is not the readiness authority`);
}
}
return {
ready: missing.length === 0,
host: expectedHost,
serviceName: dns.serviceName,
namespace: dns.namespace,
port: dns.port,
selectorless: service ? service.spec?.selector === undefined : false,
source: alias.source,
serviceName: alias.serviceName,
namespace: alias.namespace,
port: alias.port,
portName: alias.portName,
requiredForReadiness: alias.requiredForReadiness,
usedForProbe: alias.usedForProbe,
servicePresent: Boolean(service),
secretMaterialRead: false,
liveDbEvidence: false,
missing,
+55 -3
View File
@@ -305,6 +305,7 @@ function inspectCloudApiDbContract(deploy) {
networkAttempted: false,
result: "manifest_only_not_attempted",
classification: "manifest_only",
endpointSource: DEV_DB_ENV_CONTRACT.endpointAuthority.source,
probeType: "tcp-connect",
endpointRedacted: true,
valueRedacted: true,
@@ -321,6 +322,28 @@ function inspectCloudApiDbContract(deploy) {
connectionChecked: false,
connectionAttempted: false,
connectionResult: connection.result,
endpointSource: DEV_DB_ENV_CONTRACT.endpointAuthority.source,
endpoint: {
authoritative: {
source: DEV_DB_ENV_CONTRACT.endpointAuthority.source,
env: DEV_DB_ENV_CONTRACT.endpointAuthority.env,
requiredForReadiness: true,
usedForProbe: true,
endpointRedacted: true,
valueRedacted: true
}
},
optionalPublicDnsAlias: {
source: DEV_DB_ENV_CONTRACT.dns.source,
serviceName: DEV_DB_ENV_CONTRACT.dns.serviceName,
namespace: DEV_DB_ENV_CONTRACT.dns.namespace,
port: DEV_DB_ENV_CONTRACT.dns.port,
portName: DEV_DB_ENV_CONTRACT.dns.portName,
requiredForReadiness: false,
usedForProbe: false,
envPresent: false,
readyGate: "not_readiness_authority"
},
fields: [
{
name: "HWLAB_CLOUD_DB_URL",
@@ -475,9 +498,25 @@ function summarizeRuntimeDbReadiness(db, secretPresence = unknownDbSecretPresenc
const connectionResult = db.connectionResult ?? db.connection?.result ?? (connectionAttempted ? "unknown" : "not_attempted");
const connectionClassification =
db.connection?.classification ?? classificationForRuntimeDb(db, connectionAttempted, connectionResult);
const endpointSource =
db.endpointSource ?? db.connection?.endpointSource ?? db.endpoint?.authoritative?.source ?? DEV_DB_ENV_CONTRACT.endpointAuthority.source;
const optionalPublicDnsAlias = db.optionalPublicDnsAlias ?? db.endpoint?.optionalPublicDnsAlias ?? {
source: DEV_DB_ENV_CONTRACT.dns.source,
serviceName: DEV_DB_ENV_CONTRACT.dns.serviceName,
namespace: DEV_DB_ENV_CONTRACT.dns.namespace,
port: DEV_DB_ENV_CONTRACT.dns.port,
portName: DEV_DB_ENV_CONTRACT.dns.portName,
requiredForReadiness: false,
usedForProbe: false,
envPresent: false,
readyGate: "not_readiness_authority"
};
const liveConnected = Boolean(db.liveConnected ?? db.connected ?? db.ready);
const blockerMessage = liveConnected ? null : db.blocker ?? blockerForRuntimeDb(db, connectionAttempted, connectionResult);
const status = liveConnected ? "pass" : "blocked";
const authorityReady = endpointSource === DEV_DB_ENV_CONTRACT.endpointAuthority.source;
const blockerMessage = liveConnected && authorityReady
? null
: db.blocker ?? (authorityReady ? blockerForRuntimeDb(db, connectionAttempted, connectionResult) : "DB readiness did not use the Secret URL host authority");
const status = liveConnected && authorityReady ? "pass" : "blocked";
const secretRef = Array.isArray(db.secretRefs) ? db.secretRefs[0] : null;
return {
@@ -495,6 +534,18 @@ function summarizeRuntimeDbReadiness(db, secretPresence = unknownDbSecretPresenc
connectionAttempted,
connectionResult,
connectionClassification,
endpointSource,
optionalPublicDnsAlias: {
source: optionalPublicDnsAlias.source ?? DEV_DB_ENV_CONTRACT.dns.source,
serviceName: optionalPublicDnsAlias.serviceName ?? DEV_DB_ENV_CONTRACT.dns.serviceName,
namespace: optionalPublicDnsAlias.namespace ?? DEV_DB_ENV_CONTRACT.dns.namespace,
port: optionalPublicDnsAlias.port ?? DEV_DB_ENV_CONTRACT.dns.port,
portName: optionalPublicDnsAlias.portName ?? DEV_DB_ENV_CONTRACT.dns.portName,
requiredForReadiness: optionalPublicDnsAlias.requiredForReadiness === true,
usedForProbe: optionalPublicDnsAlias.usedForProbe === true,
envPresent: optionalPublicDnsAlias.envPresent === true,
readyGate: optionalPublicDnsAlias.readyGate ?? "not_readiness_authority"
},
liveConnected,
valuesRedacted: db.redaction?.valuesRedacted !== false && db.safety?.valuesRedacted === true,
secretMaterialRead: false,
@@ -507,6 +558,7 @@ function summarizeRuntimeDbReadiness(db, secretPresence = unknownDbSecretPresenc
connectionAttempted,
connectionResult,
classification: connectionClassification,
endpointSource,
liveConnected,
endpointRedacted: db.connection?.endpointRedacted !== false,
valueRedacted: true
@@ -906,7 +958,7 @@ function classifyMilestoneImpact(edgeHealth) {
return {
M3: {
status: "separate_blocker",
summary: "M3 still requires real DEV hardware trusted-loop operation/trace/audit/evidence; DB DNS failure and #143 provider Secret absence do not prove or clear M3."
summary: "M3 still requires real DEV hardware trusted-loop operation/trace/audit/evidence; DB Secret URL host readiness failure and #143 provider Secret absence do not prove or clear M3."
},
M4: {
status: dbBlocked || providerBlocked ? "blocked" : "not_proven",
+59 -1
View File
@@ -28,6 +28,7 @@ test("runtime DB readiness preserves dns resolution classification", () => {
attempted: true,
result: "dns_error",
classification: "dns_resolution_failed",
endpointSource: "secret-url-host",
endpointRedacted: true,
valueRedacted: true
},
@@ -49,13 +50,70 @@ test("runtime DB readiness preserves dns resolution classification", () => {
assert.equal(readiness.status, "blocked");
assert.equal(readiness.connectionResult, "dns_error");
assert.equal(readiness.connectionClassification, "dns_resolution_failed");
assert.equal(readiness.endpointSource, "secret-url-host");
assert.equal(readiness.optionalPublicDnsAlias.source, "optional-public-dns-alias");
assert.equal(readiness.optionalPublicDnsAlias.requiredForReadiness, false);
assert.equal(readiness.optionalPublicDnsAlias.usedForProbe, false);
assert.equal(readiness.liveConnected, false);
assert.equal(readiness.liveDbEvidence, false);
assert.equal(readiness.secretMaterialRead, false);
assert.equal(readiness.evidence[0].classification, "dns_resolution_failed");
assert.equal(readiness.evidence[0].endpointSource, "secret-url-host");
});
test("parallel blockers keep DB DNS and provider Secret gaps independent", () => {
test("runtime DB readiness does not pass when live success uses a non-authoritative DB endpoint source", () => {
const readiness = __testHooks.summarizeRuntimeDbReadiness(
{
configReady: true,
ready: true,
connected: true,
liveConnected: true,
liveDbEvidence: true,
connectionAttempted: true,
connectionResult: "connected",
endpointSource: "optional-public-dns-alias",
fields: [
{ name: "HWLAB_CLOUD_DB_URL", present: true },
{ name: "HWLAB_CLOUD_DB_SSL_MODE", present: true }
],
secretRefs: [
{
env: "HWLAB_CLOUD_DB_URL",
secretName: "hwlab-cloud-api-dev-db",
secretKey: "database-url",
present: true,
envInjected: true
}
],
connection: {
attempted: true,
result: "connected",
classification: "tcp_connected",
endpointSource: "optional-public-dns-alias",
endpointRedacted: true,
valueRedacted: true
},
redaction: { valuesRedacted: true },
safety: { valuesRedacted: true, liveDbEvidence: true }
},
{
observable: true,
secretName: "hwlab-cloud-api-dev-db",
secretKey: "database-url",
secretPresent: true,
secretKeyPresent: true,
secretValueRead: false,
redacted: true
}
);
assert.equal(readiness.status, "blocked");
assert.equal(readiness.liveConnected, true);
assert.equal(readiness.endpointSource, "optional-public-dns-alias");
assert.match(readiness.blocker, /Secret URL host/u);
});
test("parallel blockers keep DB readiness and provider Secret gaps independent", () => {
const edgeHealth = {
runtimeDbReadiness: {
status: "blocked",
@@ -841,7 +841,11 @@ function buildDoD(reports, milestones, blockers) {
artifactIdentity.targetCoverage?.covered !== false &&
artifactIdentity.artifactCatalog?.matchesTarget !== false;
const cloudApiDb = cloudApiDbStatus(reports);
const dbReady = cloudApiDb.ready === true && cloudApiDb.connected === true && cloudApiDb.liveDbEvidence === true;
const dbReady =
cloudApiDb.ready === true &&
cloudApiDb.connected === true &&
cloudApiDb.endpointSource === "secret-url-host" &&
cloudApiDb.liveDbEvidence === true;
const m3Live = statusIsPass(reports.devM3Hardware.liveOperation?.status);
const m4Live = statusIsPass(reports.devM4Agent.livePreflight?.status);
@@ -885,7 +889,7 @@ function buildDoD(reports, milestones, blockers) {
id: "cloud-api-db-ready",
status: dbReady ? "pass" : "blocked",
evidenceLevel: dbReady ? "DEV-LIVE" : "BLOCKED",
summary: `cloud-api DB status=${cloudApiDb.status}; ready=${cloudApiDb.ready}; connected=${cloudApiDb.connected}; liveDbEvidence=${cloudApiDb.liveDbEvidence}.`
summary: `cloud-api DB status=${cloudApiDb.status}; ready=${cloudApiDb.ready}; connected=${cloudApiDb.connected}; endpointSource=${cloudApiDb.endpointSource}; liveDbEvidence=${cloudApiDb.liveDbEvidence}.`
},
{
id: "m3-hardware-trusted-loop",
@@ -921,6 +925,7 @@ function cloudApiDbStatus(reports) {
connected: db.connected === true || db.liveConnected === true,
configReady: db.configReady === true,
connectionChecked: db.connectionChecked === true,
endpointSource: db.endpointSource ?? db.connection?.endpointSource ?? "unknown",
liveDbEvidence: db.liveDbEvidence === true
};
}
@@ -929,7 +934,7 @@ function buildCurrentDevLayering(reports, blockers) {
const m2EndpointLive = hasCurrentM2EndpointEvidence(reports.devM2Smoke);
const edgeLive = hasCurrentLiveEdgeEvidence(reports.devEdgeHealth);
const cloudDb = cloudApiDbStatus(reports);
const dbReady = cloudDb.ready && cloudDb.connected && cloudDb.liveDbEvidence;
const dbReady = cloudDb.ready && cloudDb.connected && cloudDb.endpointSource === "secret-url-host" && cloudDb.liveDbEvidence;
const m3Live = statusIsPass(reports.devM3Hardware.liveOperation?.status);
const m4Live = statusIsPass(reports.devM4Agent.livePreflight?.status);
const artifactIdentity = reports.devPreflight.artifactIdentity;
@@ -962,7 +967,7 @@ function buildCurrentDevLayering(reports, blockers) {
label: "DB live/degraded",
status: dbReady ? "pass" : "blocked",
evidenceLevel: dbReady ? "DEV-LIVE" : "BLOCKED",
summary: `cloud-api DB status=${cloudDb.status}; configReady=${cloudDb.configReady}; ready=${cloudDb.ready}; connected=${cloudDb.connected}; liveDbEvidence=${cloudDb.liveDbEvidence}.`,
summary: `cloud-api DB status=${cloudDb.status}; configReady=${cloudDb.configReady}; ready=${cloudDb.ready}; connected=${cloudDb.connected}; endpointSource=${cloudDb.endpointSource}; liveDbEvidence=${cloudDb.liveDbEvidence}.`,
evidence: reports.devM5Gate.devPreconditions?.evidence?.filter((line) => line.includes("/health/live") || line.includes("DB")) ?? [],
nextRequired: "Provide live DB connection evidence through redacted health output; route reachability alone is insufficient."
},
@@ -1079,11 +1084,12 @@ function buildMilestoneBlockerClassification(reports) {
status: m4Live ? "pass" : "blocked",
currentLevel: m4Live ? "DEV-LIVE" : "BLOCKED",
blockerClass: m4Live ? "cleared" : "db-live-readiness",
dependency: "Cloud API /health/live must report DB ready=true, connected=true, and liveDbEvidence=true before live agent scheduling/evidence closure.",
dependency: "Cloud API /health/live must report DB ready=true, connected=true, endpointSource=secret-url-host, and liveDbEvidence=true before live agent scheduling/evidence closure.",
evidence: [
`db.status=${cloudDb.status}`,
`db.ready=${cloudDb.ready}`,
`db.connected=${cloudDb.connected}`,
`db.endpointSource=${cloudDb.endpointSource}`,
`db.liveDbEvidence=${cloudDb.liveDbEvidence}`
],
nextRequired: "Repair DB live readiness and rerun the M4 live preflight without scheduling a DEV agent task before preconditions pass.",
@@ -1157,7 +1163,7 @@ function fallbackAction(scope) {
if (scope === "base-image") return "Preload or tag node:20-bookworm-slim and rerun the base-image and artifact publish preflights.";
if (scope.includes("artifact")) return "Publish DEV artifacts for every frozen HWLAB service and record immutable registry digests.";
if (scope.includes("edge") || scope.includes("ingress") || scope.includes("frp")) return "Repair frp/master-edge/D601 router path and rerun read-only DEV edge health.";
if (scope.includes("cloud-api-db")) return "Configure DEV cloud-api DB env readiness and rerun health/preflight without exposing secrets.";
if (scope.includes("cloud-api-db")) return "Configure DEV cloud-api DB env readiness and Secret URL host connectivity, then rerun health/preflight without exposing secrets.";
if (scope === "db-live") return "Repair DEV cloud-api DB live readiness, then rerun the read-only health and M4 preflight reports without exposing secret values.";
if (scope === "m3-patch-panel-wiring") return "Load/apply DEV patch-panel wiring for res_boxsimu_1:DO1 -> res_boxsimu_2:DI1, then rerun the bounded DEV M3 smoke.";
if (scope === "m3-box-simu-identity") return "Fix DEV box-simu instance identity so direct endpoints expose distinct res_boxsimu_1 and res_boxsimu_2 resources.";
@@ -1173,8 +1179,8 @@ function evidenceRequiredFor(scope) {
if (scope === "hwlab-router" || scope === "hwlab-tunnel-client" || scope === "hwlab-edge-proxy") return "Real repo entrypoints or dedicated Dockerfiles for route services, followed by artifact preflight.";
if (scope.includes("artifact") || scope === "ghcr") return "Artifact publish report with ciPublished=true, registryVerified=true, and sha256 digest for each frozen service ID.";
if (scope.includes("kubectl") || scope.includes("k3s")) return "Read-only kubectl/k3s report proving pods/services/configmaps are observable in hwlab-dev without reading Secrets.";
if (scope.includes("cloud-api-db")) return "Cloud API health/live output showing DB env ready and redacted secret references, without secret material.";
if (scope === "db-live") return "Cloud API /health/live output with ready=true, connected=true, liveDbEvidence=true, and redacted secret references.";
if (scope.includes("cloud-api-db")) return "Cloud API health/live output showing DB env ready, endpointSource=secret-url-host, redacted secret references, and no secret material.";
if (scope === "db-live") return "Cloud API /health/live output with ready=true, connected=true, endpointSource=secret-url-host, liveDbEvidence=true, and redacted secret references.";
if (scope === "m3-patch-panel-wiring") return "Read-only patch-panel /status and /wiring showing active res_boxsimu_1:DO1 -> res_boxsimu_2:DI1 before a bounded write/read smoke records operation, trace, audit, and evidence IDs.";
if (scope === "m3-box-simu-identity") return "Read-only direct box-simu /health/live and /status output showing distinct res_boxsimu_1 and res_boxsimu_2 resources.";
if (scope === "m3-gateway-simu-identity") return "Read-only direct gateway-simu /health/live and /status output showing two distinct gateway identities/sessions.";
+21 -41
View File
@@ -826,7 +826,7 @@ function validateCloudApiDbContract(reporter, deploy, workloads, services) {
"cloud-api-db-env-contract",
"db",
"pass",
"cloud-api DEV DB manifest declares the required env names, redacted Secret reference, and stable k3s DB DNS Service.",
"cloud-api DEV DB manifest declares the required env names and redacted Secret reference; optional cloud-api-db alias is not a readiness gate.",
evidence
);
} else {
@@ -847,7 +847,7 @@ function validateCloudApiDbContract(reporter, deploy, workloads, services) {
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, deploy/k8s/base/workloads.yaml, and deploy/k8s/base/services.yaml so they expose the required DB env names, redacted Secret reference, and stable DB Service DNS."
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."
});
}
@@ -914,7 +914,7 @@ function inspectCloudApiDbStaticContract(deploy, workloads, services) {
const missingSecretRefs = fields
.filter((field) => field.secretRef && !field.secretRef.present)
.map((field) => `${field.secretRef.secretName}/${field.secretRef.secretKey}`);
const dnsContract = inspectCloudApiDbDnsContract(deployEnv, workloadEnv, services);
const dnsContract = inspectCloudApiDbOptionalAliasContract(deployEnv, workloadEnv, services);
return {
contractVersion: DEV_DB_ENV_CONTRACT.contractVersion,
@@ -937,11 +937,9 @@ function inspectCloudApiDbStaticContract(deploy, workloads, services) {
};
}
function inspectCloudApiDbDnsContract(deployEnv, workloadEnv, services) {
const dns = DEV_DB_ENV_CONTRACT.dns;
const expectedHost = `${dns.serviceName}.${dns.namespace}.svc.cluster.local`;
const service = listManifestItems(services).find((item) => item?.metadata?.name === dns.serviceName) ?? null;
const port = service?.spec?.ports?.find((entry) => entry.name === dns.portName) ?? null;
function inspectCloudApiDbOptionalAliasContract(deployEnv, workloadEnv, services) {
const alias = DEV_DB_ENV_CONTRACT.dns;
const service = listManifestItems(services).find((item) => item?.metadata?.name === alias.serviceName) ?? null;
const actual = {
deployServiceName: deployEnv.HWLAB_CLOUD_DB_SERVICE_NAME,
deployServiceNamespace: deployEnv.HWLAB_CLOUD_DB_SERVICE_NAMESPACE,
@@ -951,43 +949,25 @@ function inspectCloudApiDbDnsContract(deployEnv, workloadEnv, services) {
workloadServiceNamespace: workloadEnv.get("HWLAB_CLOUD_DB_SERVICE_NAMESPACE")?.value,
workloadHost: workloadEnv.get("HWLAB_CLOUD_DB_HOST")?.value,
workloadPort: workloadEnv.get("HWLAB_CLOUD_DB_PORT")?.value,
serviceName: service?.metadata?.name,
serviceNamespace: service?.metadata?.namespace,
serviceType: service?.spec?.type,
serviceSelector: service?.spec?.selector ?? null,
portName: port?.name,
port: port?.port,
targetPort: port?.targetPort
serviceName: service?.metadata?.name
};
const checks = [
["deployEnv.HWLAB_CLOUD_DB_SERVICE_NAME", actual.deployServiceName, dns.serviceName],
["deployEnv.HWLAB_CLOUD_DB_SERVICE_NAMESPACE", actual.deployServiceNamespace, dns.namespace],
["deployEnv.HWLAB_CLOUD_DB_HOST", actual.deployHost, expectedHost],
["deployEnv.HWLAB_CLOUD_DB_PORT", actual.deployPort, String(dns.port)],
["workloadEnv.HWLAB_CLOUD_DB_SERVICE_NAME", actual.workloadServiceName, dns.serviceName],
["workloadEnv.HWLAB_CLOUD_DB_SERVICE_NAMESPACE", actual.workloadServiceNamespace, dns.namespace],
["workloadEnv.HWLAB_CLOUD_DB_HOST", actual.workloadHost, expectedHost],
["workloadEnv.HWLAB_CLOUD_DB_PORT", actual.workloadPort, String(dns.port)],
["Service.metadata.name", actual.serviceName, dns.serviceName],
["Service.metadata.namespace", actual.serviceNamespace, dns.namespace],
["Service.spec.type", actual.serviceType, "ClusterIP"],
["Service.spec.selector", actual.serviceSelector, null],
["Service.port.name", actual.portName, dns.portName],
["Service.port.port", actual.port, dns.port],
["Service.port.targetPort", actual.targetPort, dns.portName]
];
const missing = checks
.filter(([, actualValue, expectedValue]) => !Object.is(actualValue, expectedValue))
.map(([name, actualValue, expectedValue]) => `${name} expected ${expectedValue} got ${actualValue ?? "missing"}`);
const missing = [];
for (const [name, value] of Object.entries(actual)) {
if (value !== undefined) {
missing.push(`${name} must be absent because ${alias.serviceName} is not the readiness authority`);
}
}
return {
ready: missing.length === 0,
host: expectedHost,
serviceName: dns.serviceName,
namespace: dns.namespace,
port: dns.port,
portName: dns.portName,
selectorless: service ? service.spec?.selector === undefined : false,
source: alias.source,
serviceName: alias.serviceName,
namespace: alias.namespace,
port: alias.port,
portName: alias.portName,
requiredForReadiness: alias.requiredForReadiness,
usedForProbe: alias.usedForProbe,
servicePresent: Boolean(service),
secretMaterialRead: false,
liveDbEvidence: false,
missing,
+17 -31
View File
@@ -172,19 +172,19 @@ assert.equal(cloudApi.env.HWLAB_IMAGE_TAG, deployManifest.commitId.slice(0, 7),
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_CONTRACT, "dev-redacted-presence-only", "cloud-api DB contract marker");
assert.equal(cloudApi.env.HWLAB_CLOUD_DB_SERVICE_NAME, DEV_DB_ENV_CONTRACT.dns.serviceName, "cloud-api DB service name");
assert.equal(cloudApi.env.HWLAB_CLOUD_DB_SERVICE_NAMESPACE, DEV_DB_ENV_CONTRACT.dns.namespace, "cloud-api DB service namespace");
assert.equal(cloudApi.env.HWLAB_CLOUD_DB_HOST, DEV_DB_ENV_CONTRACT.dns.host, "cloud-api DB stable host");
assert.equal(cloudApi.env.HWLAB_CLOUD_DB_PORT, String(DEV_DB_ENV_CONTRACT.dns.port), "cloud-api DB stable port");
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_SERVICE_NAME?.value, DEV_DB_ENV_CONTRACT.dns.serviceName, "cloud-api workload DB service name");
assert.equal(cloudApiWorkloadEnv.HWLAB_CLOUD_DB_SERVICE_NAMESPACE?.value, DEV_DB_ENV_CONTRACT.dns.namespace, "cloud-api workload DB service namespace");
assert.equal(cloudApiWorkloadEnv.HWLAB_CLOUD_DB_HOST?.value, DEV_DB_ENV_CONTRACT.dns.host, "cloud-api workload DB host");
assert.equal(cloudApiWorkloadEnv.HWLAB_CLOUD_DB_PORT?.value, String(DEV_DB_ENV_CONTRACT.dns.port), "cloud-api workload DB port");
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");
assertCloudApiDbDnsContract(k8sServices, cloudApi.env);
assert.equal(cloudApi.env.HWLAB_CLOUD_DB_SERVICE_NAME, undefined, "cloud-api DB alias service name is optional");
assert.equal(cloudApi.env.HWLAB_CLOUD_DB_SERVICE_NAMESPACE, undefined, "cloud-api DB alias namespace is optional");
assert.equal(cloudApi.env.HWLAB_CLOUD_DB_HOST, undefined, "cloud-api DB alias host is optional");
assert.equal(cloudApi.env.HWLAB_CLOUD_DB_PORT, undefined, "cloud-api DB alias port is optional");
assert.equal(cloudApiWorkloadEnv.HWLAB_CLOUD_DB_SERVICE_NAME, undefined, "cloud-api workload DB alias service name is optional");
assert.equal(cloudApiWorkloadEnv.HWLAB_CLOUD_DB_SERVICE_NAMESPACE, undefined, "cloud-api workload DB alias namespace is optional");
assert.equal(cloudApiWorkloadEnv.HWLAB_CLOUD_DB_HOST, undefined, "cloud-api workload DB alias host is optional");
assert.equal(cloudApiWorkloadEnv.HWLAB_CLOUD_DB_PORT, undefined, "cloud-api workload DB alias port is optional");
assertCloudApiDbOptionalAlias(k8sServices);
assert.equal(cloudApi.env.HWLAB_CODE_AGENT_PROVIDER, "openai", "cloud-api Code Agent provider");
assert.equal(cloudApi.env.HWLAB_CODE_AGENT_MODEL, DEV_CODE_AGENT_PROVIDER_CONTRACT.model, "cloud-api Code Agent model");
assert.equal(
@@ -223,28 +223,14 @@ function getWorkloadEnv(workloads, serviceId) {
return {};
}
function assertCloudApiDbDnsContract(services, env) {
const dns = DEV_DB_ENV_CONTRACT.dns;
const service = listItems(services).find((item) => item?.metadata?.name === dns.serviceName);
assert.ok(service, `deploy/k8s/base/services.yaml must define Service/${dns.serviceName}`);
assert.equal(service.metadata.namespace, dns.namespace, "cloud-api DB Service namespace");
assert.equal(service.kind, "Service", "cloud-api DB Service kind");
assert.equal(service.spec?.type, "ClusterIP", "cloud-api DB Service type");
assert.equal(service.spec?.selector, undefined, "cloud-api DB Service must be selectorless until DB endpoints are provisioned");
assert.equal(service.metadata?.labels?.["hwlab.pikastech.local/source-contract"], "db-dns", "cloud-api DB Service source-contract label");
const port = service.spec?.ports?.find((entry) => entry.name === dns.portName);
assert.ok(port, `Service/${dns.serviceName} must expose ${dns.portName}`);
assert.equal(port.port, dns.port, "cloud-api DB Service port");
assert.equal(port.targetPort, dns.portName, "cloud-api DB Service targetPort");
const expectedHost = `${dns.serviceName}.${dns.namespace}.svc.cluster.local`;
assert.equal(dns.host, expectedHost, "DB DNS contract host matches service namespace");
assert.equal(env.HWLAB_CLOUD_DB_HOST, expectedHost, "cloud-api DB host env matches Service DNS");
assert.equal(env.HWLAB_CLOUD_DB_SERVICE_NAME, service.metadata.name, "cloud-api DB service env matches Service name");
assert.equal(env.HWLAB_CLOUD_DB_SERVICE_NAMESPACE, service.metadata.namespace, "cloud-api DB namespace env matches Service namespace");
assert.equal(env.HWLAB_CLOUD_DB_PORT, String(port.port), "cloud-api DB port env matches Service port");
const secretUrl = parseDbUrlContract(`postgres://${env.HWLAB_CLOUD_DB_HOST}:${env.HWLAB_CLOUD_DB_PORT}/hwlab`);
assert.equal(secretUrl.ok, true, "cloud-api DB stable host/port must form a supported postgres URL");
function assertCloudApiDbOptionalAlias(services) {
const alias = DEV_DB_ENV_CONTRACT.dns;
const service = listItems(services).find((item) => item?.metadata?.name === alias.serviceName);
assert.equal(DEV_DB_ENV_CONTRACT.endpointAuthority.source, "secret-url-host", "cloud-api DB runtime authority is the Secret URL host");
assert.equal(DEV_DB_ENV_CONTRACT.endpointAuthority.env, "HWLAB_CLOUD_DB_URL", "cloud-api DB runtime authority env");
assert.equal(alias.requiredForReadiness, false, "cloud-api DB alias is not a readiness requirement");
assert.equal(alias.usedForProbe, false, "cloud-api DB alias is not the runtime TCP probe source");
assert.equal(service, undefined, `Service/${alias.serviceName} is optional until this repo owns endpoints and rollout/apply contract`);
}
function assertCodeAgentProviderWorkloadContract(env) {
+30 -27
View File
@@ -14,7 +14,6 @@ const forbiddenRuntimeSubstitutes = Object.freeze([
"provider-gateway",
"microservice-proxy"
]);
const dbDnsComponent = "cloud-api-db";
async function readText(relativePath) {
return readFile(path.join(repoRoot, relativePath), "utf8");
@@ -125,31 +124,17 @@ function labelsFor(resource, label) {
}
function assertMetadataServiceId(resource, expectedServiceId, label) {
assert.equal(resource.metadata?.name, expectedServiceId, `${label}.metadata.name must match service id`);
if (!resource.metadata?.labels?.["hwlab.pikastech.local/instance-id"]) {
assert.equal(resource.metadata?.name, expectedServiceId, `${label}.metadata.name must match service id`);
} else {
assert.ok(resource.metadata?.name.startsWith(`${expectedServiceId}-`), `${label}.metadata.name must include service id prefix`);
}
assertDevNamespace(resource.metadata?.namespace, `${label}.metadata.namespace`);
const labels = labelsFor(resource, label);
assert.equal(labels[serviceIdLabel], expectedServiceId, `${label} service-id label`);
assert.equal(labels["app.kubernetes.io/name"], expectedServiceId, `${label} app name label`);
}
function assertDbDnsService(service) {
const dns = DEV_DB_ENV_CONTRACT.dns;
assert.equal(service.metadata?.name, dns.serviceName, "DB DNS Service name");
assertDevNamespace(service.metadata?.namespace, "DB DNS Service namespace");
assert.equal(service.metadata?.labels?.["app.kubernetes.io/name"], dbDnsComponent, "DB DNS app label");
assert.equal(service.metadata?.labels?.["hwlab.pikastech.local/component"], dbDnsComponent, "DB DNS component label");
assert.equal(service.metadata?.labels?.["hwlab.pikastech.local/source-contract"], "db-dns", "DB DNS source-contract label");
assert.equal(service.metadata?.labels?.[serviceIdLabel], undefined, "DB DNS Service is not a frozen HWLAB runtime service-id");
assert.equal(service.spec?.type, "ClusterIP", "DB DNS Service type");
assert.equal(service.spec?.selector, undefined, "DB DNS Service stays selectorless until endpoints are provisioned");
const ports = service.spec?.ports;
assertArray(ports, "DB DNS Service ports");
assert.equal(ports.length, 1, "DB DNS Service exposes one port");
assert.equal(ports[0].name, dns.portName, "DB DNS Service port name");
assert.equal(ports[0].port, dns.port, "DB DNS Service port");
assert.equal(ports[0].targetPort, dns.portName, "DB DNS Service targetPort");
}
function assertTemplateServiceId(workload, expectedServiceId, label) {
const templateLabels = workload.spec?.template?.metadata?.labels;
assertObject(templateLabels, `${label}.spec.template.metadata.labels`);
@@ -311,24 +296,42 @@ function assertServices(services, guard) {
assert.equal(services.kind, "List", "services kind");
assertArray(services.items, "services items");
const runtimeServices = services.items.filter((item) => item.metadata?.name !== dbDnsComponent);
const serviceIds = runtimeServices.map((item) => item.metadata?.labels?.[serviceIdLabel]);
assertUnique(serviceIds, "k8s service ids");
const runtimeServices = services.items;
const serviceNames = runtimeServices.map((item) => item.metadata?.name);
const serviceIds = [...new Set(runtimeServices.map((item) => item.metadata?.labels?.[serviceIdLabel]))];
assertUnique(serviceNames, "k8s service names");
assertSameMembers(serviceIds, guard.requiredK3sSkeleton.requiredServiceServiceIds, "k8s service ids");
const dbDnsService = services.items.find((item) => item.metadata?.name === dbDnsComponent);
assert.ok(dbDnsService, "k8s services must include selectorless cloud-api-db DNS Service");
assertDbDnsService(dbDnsService);
assert.equal(
services.items.some((item) => item.metadata?.name === DEV_DB_ENV_CONTRACT.dns.serviceName),
false,
"cloud-api-db is an optional future alias and is not required in the current runtime boundary"
);
assert.equal(DEV_DB_ENV_CONTRACT.endpointAuthority.source, "secret-url-host", "DB readiness authority must be the Secret URL host");
assert.equal(DEV_DB_ENV_CONTRACT.dns.requiredForReadiness, false, "DB DNS alias must not be a readiness hard requirement");
assert.equal(DEV_DB_ENV_CONTRACT.dns.usedForProbe, false, "DB DNS alias must not be the runtime probe target");
for (const service of runtimeServices) {
const serviceId = service.metadata?.labels?.[serviceIdLabel];
assertServiceId(serviceId, `k8s service ${service.metadata?.name}`);
assertMetadataServiceId(service, serviceId, `k8s service ${serviceId}`);
assertNoExternalNameSubstitute(service, `k8s service ${serviceId}`);
assert.equal(service.spec?.selector?.["app.kubernetes.io/name"], serviceId, `${serviceId} selector`);
if (service.metadata?.labels?.["hwlab.pikastech.local/instance-id"]) {
assert.match(
service.spec?.selector?.["statefulset.kubernetes.io/pod-name"],
new RegExp(`^${escapeRegExp(serviceId)}-\\d+$`),
`${serviceId} indexed selector`
);
} else {
assert.equal(service.spec?.selector?.["app.kubernetes.io/name"], serviceId, `${serviceId} selector`);
}
}
}
function escapeRegExp(value) {
return String(value).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
function assertDevHealthConfig(configMap) {
assert.equal(configMap.kind, "ConfigMap", "dev health contract kind");
assertDevNamespace(configMap.metadata?.namespace, "dev health contract namespace");