fix: expose hwpod platform db secret status
This commit is contained in:
@@ -16,7 +16,7 @@ CI/CD、GitOps、rollout、artifact 发布、PR 合并后的 runtime lane 滚动
|
||||
|
||||
当现有 CLI 对某个 CI/CD 操作缺字段、缺动作、缺状态或缺权限时,处理顺序是先补 CLI,再执行发布或治理动作。临时低层 route 写操作只允许用于一次性止血,并且必须随后把稳定能力补进 CLI 与本参考文档;不能把手工 `kubectl apply/delete/annotate`、原生 GitHub CLI、手写 REST 请求或 registry shell 脚本沉淀成长期流程。长时观察仍遵守 60 秒短查询和 submit-and-poll 语义,不用单个 `trans`/`tran` 等待完整 PipelineRun 或 Argo rollout 结束。
|
||||
|
||||
`hwlab nodes control-plane allow-endpoint-bridge --node G14 --lane v03 [--dry-run|--confirm]` 是 v03 platform PostgreSQL bridge 的受控收敛入口,用于让 Argo 跟踪固定 `EndpointSlice/g14-platform-postgres-host`,并清理旧 `Endpoints/g14-platform-postgres` 及其派生的随机 EndpointSlice。`hwlab nodes secret cleanup-owned-postgres --node G14 --lane v03 [--dry-run|--confirm]` 是 v03 迁移到 G14 platform PostgreSQL 后清理旧 repo-owned Postgres StatefulSet/Service/ConfigMap/Secret/PVC 的受控入口。迁移后的 `hwlab-cloud-api-v03-db` 和 `hwlab-v03-openfga` SecretRef 来自 G14 host platform DB 凭据文件,不再从 lane-local Postgres Secret 派生;v03+ 的 `hwlab nodes secret ensure --name hwlab-cloud-api-v03-db|hwlab-v03-openfga` 旧路径已删除,status 只做 redacted SecretRef 与 `g14-platform-postgres` Service、固定 EndpointSlice 和旧 Endpoints 缺席观测。平台 DB 运行、SecretRef 轮换边界和 health 验证见 `docs/reference/g14-platform-db.md`。
|
||||
`hwlab nodes control-plane allow-endpoint-bridge --node G14 --lane v03 [--dry-run|--confirm]` 是 v03 platform PostgreSQL bridge 的受控收敛入口,用于让 Argo 跟踪固定 `EndpointSlice/g14-platform-postgres-host`,并清理旧 `Endpoints/g14-platform-postgres` 及其派生的随机 EndpointSlice。`hwlab nodes secret cleanup-owned-postgres --node G14 --lane v03 [--dry-run|--confirm]` 是 v03 迁移到 G14 platform PostgreSQL 后清理旧 repo-owned Postgres StatefulSet/Service/ConfigMap/Secret/PVC 的受控入口。迁移后的 `hwlab-cloud-api-v03-db`、`hwlab-v03-openfga` 和 `hwpod-v03-db` SecretRef 来自 G14 host platform DB 凭据文件,不再从 lane-local Postgres Secret 派生;v03+ 的 `hwlab nodes secret ensure --name hwlab-cloud-api-v03-db|hwlab-v03-openfga|hwpod-v03-db` 旧路径已删除,status 只做 redacted SecretRef 与 `g14-platform-postgres` Service、固定 EndpointSlice 和旧 Endpoints 缺席观测。平台 DB 运行、SecretRef 轮换边界和 health 验证见 `docs/reference/g14-platform-db.md`。
|
||||
|
||||
`hwlab nodes secret status|ensure --node G14 --lane v03 --name hwlab-v03-code-agent-provider` 是 v03 Code Agent / MoonBridge provider SecretRef 的受控 bootstrap 入口;`ensure` 只从集群内既有 `hwlab-v02/hwlab-v02-code-agent-provider` 复制 `openai-api-key`、`opencode-api-key` 到 lane-local Secret,输出仅披露 source/target Secret 名、key presence、decoded byte count、mutation 和后续命令,禁止打印 base64、解码值、完整 API key 或可复用凭据。OpenFGA 和 master admin API key 继续使用同一命名空间下的 `hwlab nodes secret ... --name hwlab-v03-openfga|hwlab-v03-master-server-admin-api-key`。
|
||||
|
||||
@@ -62,7 +62,7 @@ CI/CD、GitOps、rollout、artifact 发布、PR 合并后的 runtime lane 滚动
|
||||
创建 PipelineRun 前会读取 `devops-infra` mirror refs,若 `localV02` 未等于当前 source commit,则自动执行一次受控 manual `git-mirror sync` Job 并复核 ref,复核失败时停止触发,避免 Tekton `prepare-source` 已知失败;services 参数只包含 v02 runtime service matrix,`hwlab-cli` 是固定 repo 短连接源码工具,不进入 PipelineRun service build。
|
||||
`--dry-run` 只报告是否会 pre-sync,不创建 Job;confirmed trigger 默认创建 `.state/jobs/` 异步 job 并立刻返回 `job.id`、`statusCommand`、stdout/stderr 路径,避免 git mirror pre-sync 或 PipelineRun 创建期间长时间阻塞;`--wait` 路径也必须向 stderr 输出 `hwlab.v02.trigger.progress` JSON 事件,覆盖 `control-plane-refresh`、`git-mirror-pre-sync` 和 `create-pipelinerun`,避免异步 job 长时间只有启动命令而无法判断卡点;默认 JSON 必须对 `manifest_b64`、长脚本和远端 stdout/stderr 做有界摘要,保留长度与 hash,最终 trigger 结果只返回阶段摘要和关键 tail,完整内容通过 job stdout/stderr 文件渐进披露;只有现场同步调试才显式加 `--wait`;旧 `rerun-current` 只作为输入别名保留。PipelineRun `Completed`、Argo `Synced/Healthy` 和 `webAssets.ok=true` 只证明 G14 runtime 已更新;交付收口还必须用 `hwlab g14 git-mirror status` 查看 `cache.summary.pendingFlush`,若为 true,继续执行受控 `hwlab g14 git-mirror flush --confirm` 并用 job status 轮询到 `pendingFlush=false`。
|
||||
- `hwlab g14 control-plane runtime-migration --lane v02 [--dry-run|--allow-live-db-read --dry-run|--confirm]` 只通过 `hwlab-v02` namespace 当前 `deployment/hwlab-cloud-api -c hwlab-cloud-api` 内 repo-owned migration CLI 执行;不读取或打印 Secret 值、不触碰 PROD、不绕到手工 `psql`。
|
||||
- `hwlab g14 secret status|ensure --lane v02 --name hwlab-v02-openfga|hwlab-v02-master-server-admin-api-key [--dry-run|--confirm]` 和 `hwlab nodes secret status|ensure --node G14 --lane v03 --name hwlab-v03-master-server-admin-api-key [--dry-run|--confirm]` 是 HWLAB runtime lane SecretRef bootstrap 的保留入口。v03+ Cloud API/OpenFGA datastore SecretRef 已迁移到 G14 platform PostgreSQL,`hwlab nodes secret status --node G14 --lane v03 --name hwlab-cloud-api-v03-db|hwlab-v03-openfga` 只做 redacted SecretRef 与 `g14-platform-postgres` bridge 观测;旧 `ensure` 路径已删除,不再从 `hwlab-v03-postgres` Secret 或 StatefulSet 派生。平台库凭据、桥接 Service 和 SecretRef 轮换边界见 `docs/reference/g14-platform-db.md`。master server admin API key preset 确保本机 `/root/.config/hwlab-v0x/master-server-admin-api-key.env` 以 0600 保存 `HWLAB_API_KEY`,并同步到对应 lane 的 `*-master-server-admin-api-key/api-key`。`status` 只返回 key 是否存在、解码后字节数、key prefix、bridge 存在性和 runtime health 相关结果,永远不读取、不打印、不回传 secret 明文。`hwlab nodes secret cleanup-owned-postgres --node G14 --lane v03 [--dry-run|--confirm]` 是 v0.3+ 迁移到 G14 平台 Postgres 后的受控残留清理入口,精确删除旧 repo-owned `hwlab-v03-postgres` StatefulSet/Service/ConfigMap/Secret 和 `data-hwlab-v03-postgres-0` PVC;它要求 `g14-platform-postgres` Service 已存在,默认 dry-run,不触碰平台数据库、OpenFGA/Cloud API 当前 SecretRef 或 GitOps desired state。`hwlab g14 secret delete --lane v02 --name <obsolete-hwlab-v02-secret> [--dry-run|--confirm]` 只用于删除确认已不被 workload 引用的 v0.2 废弃 Secret,默认 dry-run,拒绝删除 OpenFGA/Postgres/master admin API key 等必需 Secret;共享 device-pod API key 已退出当前授权路径,不再提供 ensure/bootstrap 入口。
|
||||
- `hwlab g14 secret status|ensure --lane v02 --name hwlab-v02-openfga|hwlab-v02-master-server-admin-api-key [--dry-run|--confirm]` 和 `hwlab nodes secret status|ensure --node G14 --lane v03 --name hwlab-v03-master-server-admin-api-key [--dry-run|--confirm]` 是 HWLAB runtime lane SecretRef bootstrap 的保留入口。v03+ Cloud API/OpenFGA/HWPOD datastore SecretRef 已迁移到 G14 platform PostgreSQL,`hwlab nodes secret status --node G14 --lane v03 --name hwlab-cloud-api-v03-db|hwlab-v03-openfga|hwpod-v03-db` 只做 redacted SecretRef 与 `g14-platform-postgres` bridge 观测;旧 `ensure` 路径已删除,不再从 `hwlab-v03-postgres` Secret 或 StatefulSet 派生。平台库凭据、桥接 Service 和 SecretRef 轮换边界见 `docs/reference/g14-platform-db.md`。master server admin API key preset 确保本机 `/root/.config/hwlab-v0x/master-server-admin-api-key.env` 以 0600 保存 `HWLAB_API_KEY`,并同步到对应 lane 的 `*-master-server-admin-api-key/api-key`。`status` 只返回 key 是否存在、解码后字节数、key prefix、bridge 存在性和 runtime health 相关结果,永远不读取、不打印、不回传 secret 明文。`hwlab nodes secret cleanup-owned-postgres --node G14 --lane v03 [--dry-run|--confirm]` 是 v0.3+ 迁移到 G14 平台 Postgres 后的受控残留清理入口,精确删除旧 repo-owned `hwlab-v03-postgres` StatefulSet/Service/ConfigMap/Secret 和 `data-hwlab-v03-postgres-0` PVC;它要求 `g14-platform-postgres` Service 已存在,默认 dry-run,不触碰平台数据库、OpenFGA/Cloud API/HWPOD 当前 SecretRef 或 GitOps desired state。`hwlab g14 secret delete --lane v02 --name <obsolete-hwlab-v02-secret> [--dry-run|--confirm]` 只用于删除确认已不被 workload 引用的 v0.2 废弃 Secret,默认 dry-run,拒绝删除 OpenFGA/Postgres/master admin API key 等必需 Secret;共享 device-pod API key 已退出当前授权路径,不再提供 ensure/bootstrap 入口。
|
||||
- `hwlab g14 control-plane cleanup-runs --lane v02|v03|g14|all [--min-age-minutes N] [--limit N] [--dry-run|--confirm]` 是完成态 PipelineRun 工作区 retention 入口;真实清理只删除已完成 PipelineRun,让 Tekton/local-path 回收临时 PVC,不触碰 registry storage、业务 PVC、Secret、runtime workload 或 GitOps desired state。带 `--pipeline-run <name>` 或 `--source-commit <full-sha>` 的定点清理必须先直接查询目标 PipelineRun,而不是只从全量列表过滤;不存在的目标返回 `target-pipelinerun-not-found`,未完成目标返回 `target-pipelinerun-not-terminal`,空查询和读取失败分别返回 `target-pipelinerun-query-empty` / `target-pipelinerun-query-failed`,年龄保护仍返回 `below-min-age`。`hwlab nodes control-plane cleanup-runs --node G14 --lane v03 --pipeline-run <name>` 是 v0.3 failed run 受控重试前的清理入口。
|
||||
- `hwlab g14 control-plane cleanup-released-pvs --lane all [--limit N] [--dry-run|--confirm]` 是 local-path 未自动回收后的补充 retention 入口;只列并删除 `Released`、`local-path`、`Delete`、`claimNamespace=hwlab-ci` 且 claim 名称形如 Tekton 临时 `pvc-*` 的 PV。
|
||||
- `hwlab g14 git-mirror status|apply|sync|flush [--dry-run|--confirm]` 是 `devops-infra` git mirror/relay 的受控维护入口:`apply` 渲染并 server-side apply `devops-infra/git-mirror.yaml`,同时删除遗留 `git-mirror-hwlab-sync` CronJob;`sync` 创建一次性 manual Job,把 GitHub allowlist refs 拉入本地 mirror;`flush` 创建一次性 manual Job,把本地 `v0.2-gitops` 快进推回 GitHub。
|
||||
|
||||
@@ -164,12 +164,15 @@ assertCondition(
|
||||
hwlabHelpUsage.some((line) => line.includes("hwlab nodes secret status --node G14 --lane v03 --name hwlab-v03-code-agent-provider"))
|
||||
&& hwlabHelpUsage.some((line) => line.includes("hwlab nodes secret ensure --node G14 --lane v03 --name hwlab-v03-code-agent-provider --confirm"))
|
||||
&& hwlabHelpUsage.some((line) => line.includes("hwlab nodes secret status --node G14 --lane v03 --name hwlab-cloud-api-v03-db"))
|
||||
&& hwlabHelpUsage.some((line) => line.includes("hwlab nodes secret status --node G14 --lane v03 --name hwpod-v03-db"))
|
||||
&& hwlabHelpUsage.some((line) => line.includes("hwlab nodes secret cleanup-owned-postgres --node G14 --lane v03 --dry-run"))
|
||||
&& hwlabNodeHelpJson.includes("hwlab nodes secret status --node G14 --lane v03 --name hwlab-v03-code-agent-provider")
|
||||
&& hwlabNodeHelpJson.includes("hwlab nodes secret ensure --node G14 --lane v03 --name hwlab-v03-code-agent-provider --confirm")
|
||||
&& hwlabNodeHelpJson.includes("hwlab nodes secret status --node G14 --lane v03 --name hwlab-cloud-api-v03-db")
|
||||
&& hwlabNodeHelpJson.includes("hwlab nodes secret status --node G14 --lane v03 --name hwpod-v03-db")
|
||||
&& hwlabNodeHelpJson.includes("hwlab nodes secret cleanup-owned-postgres --node G14 --lane v03 --dry-run")
|
||||
&& !hwlabNodeHelpJson.includes("hwlab nodes secret ensure --node G14 --lane v03 --name hwlab-cloud-api-v03-db --confirm")
|
||||
&& !hwlabNodeHelpJson.includes("hwlab nodes secret ensure --node G14 --lane v03 --name hwpod-v03-db --confirm")
|
||||
&& !hwlabNodeHelpJson.includes("hwlab nodes secret ensure --node G14 --lane v03 --name hwlab-v03-openfga --confirm"),
|
||||
"v0.3 node-scoped secret help must expose provider bootstrap plus platform DB status/cleanup without old DB ensure paths",
|
||||
{ hwlabHelpUsage, hwlabNodeHelp: hwlabNodeHelp() },
|
||||
@@ -219,6 +222,48 @@ assertCondition(
|
||||
"cloud-api DB Secret status must be redacted while proving native platform DB SecretRef and bridge are present",
|
||||
cloudApiDbStatus,
|
||||
);
|
||||
const hwpodDbStatus = nodeSecretStatusFromTextForTest([
|
||||
"namespace\thwlab-v03",
|
||||
"secret\thwpod-v03-db",
|
||||
"key\tdatabase-url",
|
||||
"preset\thwpod-db",
|
||||
"action\tobserved",
|
||||
"dryRun\ttrue",
|
||||
"mutation\tfalse",
|
||||
"platformDbMode\ttrue",
|
||||
"afterExists\tyes",
|
||||
"afterDatabaseUrlPresent\tyes",
|
||||
"afterDatabaseUrlBytes\t172",
|
||||
"legacyPostgresSecret\thwlab-v03-postgres",
|
||||
"legacyPostgresSecretExists\tno",
|
||||
"platformService\tg14-platform-postgres",
|
||||
"platformServiceExists\tyes",
|
||||
"platformEndpointsExists\tno",
|
||||
"platformEndpointSlice\tg14-platform-postgres-host",
|
||||
"platformEndpointSliceExists\tyes",
|
||||
"dbName\thwpod_v03",
|
||||
"dbUser\thwpod_v03_app",
|
||||
"dbHost\tg14-platform-postgres.hwlab-v03.svc.cluster.local",
|
||||
"dbHostMatchesPlatform\tyes",
|
||||
"dbNameMatchesExpected\tyes",
|
||||
"dbUserMatchesExpected\tyes",
|
||||
].join("\n"), true, 0, "");
|
||||
assertCondition(
|
||||
record(hwpodDbStatus).ok === true
|
||||
&& record(hwpodDbStatus).valuesRedacted === true
|
||||
&& record(hwpodDbStatus).platformDbMode === true
|
||||
&& record(record(hwpodDbStatus).legacyPostgresSecret).exists === false
|
||||
&& record(record(hwpodDbStatus).platformService).endpointsExist === false
|
||||
&& record(record(hwpodDbStatus).platformService).legacyEndpointsAbsent === true
|
||||
&& record(record(hwpodDbStatus).platformService).endpointSlice === "g14-platform-postgres-host"
|
||||
&& record(hwpodDbStatus).dbName === "hwpod_v03"
|
||||
&& record(hwpodDbStatus).dbUser === "hwpod_v03_app"
|
||||
&& record(hwpodDbStatus).dbHost === "g14-platform-postgres.hwlab-v03.svc.cluster.local"
|
||||
&& !JSON.stringify(hwpodDbStatus).includes("postgres://")
|
||||
&& !JSON.stringify(hwpodDbStatus).includes("password"),
|
||||
"HWPOD DB Secret status must prove the v0.3 platform DB SecretRef without exposing database-url material",
|
||||
hwpodDbStatus,
|
||||
);
|
||||
const openFgaPlatformStatus = nodeSecretStatusFromTextForTest([
|
||||
"namespace\thwlab-v03",
|
||||
"secret\thwlab-v03-openfga",
|
||||
@@ -271,6 +316,13 @@ assertCondition(
|
||||
"v0.3 cloud-api DB ensure must reject the removed lane-local Postgres path",
|
||||
removedCloudApiDbEnsure,
|
||||
);
|
||||
const removedHwpodDbEnsure = runCommand(["bun", "scripts/cli.ts", "hwlab", "nodes", "secret", "ensure", "--node", "G14", "--lane", "v03", "--name", "hwpod-v03-db", "--dry-run"], process.cwd(), { timeoutMs: 30_000 });
|
||||
assertCondition(
|
||||
removedHwpodDbEnsure.exitCode !== 0
|
||||
&& `${removedHwpodDbEnsure.stdout}\n${removedHwpodDbEnsure.stderr}`.includes("was removed after native platform DB migration"),
|
||||
"v0.3 HWPOD DB ensure must reject the removed lane-local Postgres path",
|
||||
removedHwpodDbEnsure,
|
||||
);
|
||||
const removedOpenFgaEnsure = runCommand(["bun", "scripts/cli.ts", "hwlab", "nodes", "secret", "ensure", "--node", "G14", "--lane", "v03", "--name", "hwlab-v03-openfga", "--dry-run"], process.cwd(), { timeoutMs: 30_000 });
|
||||
assertCondition(
|
||||
removedOpenFgaEnsure.exitCode !== 0
|
||||
|
||||
@@ -10221,6 +10221,7 @@ export function hwlabG14Help(): Record<string, unknown> {
|
||||
"bun scripts/cli.ts hwlab nodes secret status --node G14 --lane v03 --name hwlab-v03-master-server-admin-api-key",
|
||||
"bun scripts/cli.ts hwlab nodes secret ensure --node G14 --lane v03 --name hwlab-v03-master-server-admin-api-key --confirm",
|
||||
"bun scripts/cli.ts hwlab nodes secret status --node G14 --lane v03 --name hwlab-cloud-api-v03-db",
|
||||
"bun scripts/cli.ts hwlab nodes secret status --node G14 --lane v03 --name hwpod-v03-db",
|
||||
"bun scripts/cli.ts hwlab nodes secret cleanup-owned-postgres --node G14 --lane v03 --dry-run",
|
||||
"bun scripts/cli.ts hwlab nodes secret cleanup-owned-postgres --node G14 --lane v03 --confirm",
|
||||
"bun scripts/cli.ts hwlab nodes secret status --node G14 --lane v03 --name hwlab-v03-code-agent-provider",
|
||||
|
||||
+77
-25
@@ -6,7 +6,7 @@ import { runHwlabG14Command } from "./hwlab-g14";
|
||||
import { hwlabRuntimeLaneConfigPath, hwlabRuntimeLaneSpec, isHwlabRuntimeLane, type HwlabRuntimeLane } from "./hwlab-node-lanes";
|
||||
|
||||
type SecretAction = "status" | "ensure" | "cleanup-owned-postgres";
|
||||
type SecretPreset = "openfga" | "master-server-admin-api-key" | "code-agent-provider" | "cloud-api-db" | "owned-postgres-cleanup";
|
||||
type SecretPreset = "openfga" | "master-server-admin-api-key" | "code-agent-provider" | "cloud-api-db" | "hwpod-db" | "owned-postgres-cleanup";
|
||||
type DelegatedNodeDomain = "control-plane" | "git-mirror";
|
||||
|
||||
interface NodeSecretOptions {
|
||||
@@ -41,6 +41,11 @@ interface RuntimeSecretSpec {
|
||||
cloudApiDbUser: string;
|
||||
cloudApiDbHost: string;
|
||||
cloudApiDeployment: string;
|
||||
hwpodDbSecret: string;
|
||||
hwpodDbKey: string;
|
||||
hwpodDbName: string;
|
||||
hwpodDbUser: string;
|
||||
hwpodDbHost: string;
|
||||
codeAgentProviderSecret: string;
|
||||
codeAgentProviderSourceNamespace: string;
|
||||
codeAgentProviderSourceSecret: string;
|
||||
@@ -87,6 +92,7 @@ export function hwlabNodeHelp(): Record<string, unknown> {
|
||||
"bun scripts/cli.ts hwlab nodes secret status --node G14 --lane v03 --name hwlab-v03-openfga",
|
||||
"bun scripts/cli.ts hwlab nodes secret ensure --node G14 --lane v03 --name hwlab-v03-master-server-admin-api-key --confirm",
|
||||
"bun scripts/cli.ts hwlab nodes secret status --node G14 --lane v03 --name hwlab-cloud-api-v03-db",
|
||||
"bun scripts/cli.ts hwlab nodes secret status --node G14 --lane v03 --name hwpod-v03-db",
|
||||
"bun scripts/cli.ts hwlab nodes secret cleanup-owned-postgres --node G14 --lane v03 --dry-run",
|
||||
"bun scripts/cli.ts hwlab nodes secret cleanup-owned-postgres --node G14 --lane v03 --confirm",
|
||||
"bun scripts/cli.ts hwlab nodes secret status --node G14 --lane v03 --name hwlab-v03-code-agent-provider",
|
||||
@@ -210,7 +216,7 @@ function rewriteDelegatedNodeString(value: string, scoped: ReturnType<typeof par
|
||||
function parseSecretOptions(args: string[]): NodeSecretOptions {
|
||||
const [actionRaw] = args;
|
||||
if (actionRaw !== "status" && actionRaw !== "ensure" && actionRaw !== "cleanup-owned-postgres") {
|
||||
throw new Error("secret usage: status|ensure --node NODE --lane vNN --name hwlab-vNN-openfga|hwlab-vNN-master-server-admin-api-key|hwlab-cloud-api-vNN-db|hwlab-vNN-code-agent-provider [--dry-run|--confirm] | cleanup-owned-postgres --node NODE --lane vNN [--dry-run|--confirm]");
|
||||
throw new Error("secret usage: status|ensure --node NODE --lane vNN --name hwlab-vNN-openfga|hwlab-vNN-master-server-admin-api-key|hwlab-cloud-api-vNN-db|hwpod-vNN-db|hwlab-vNN-code-agent-provider [--dry-run|--confirm] | cleanup-owned-postgres --node NODE --lane vNN [--dry-run|--confirm]");
|
||||
}
|
||||
const node = requiredOption(args, "--node");
|
||||
assertNodeId(node);
|
||||
@@ -284,8 +290,26 @@ function parseSecretOptions(args: string[]): NodeSecretOptions {
|
||||
timeoutSeconds: positiveIntegerOption(args, "--timeout-seconds", 240, 900),
|
||||
};
|
||||
}
|
||||
if (name === spec.hwpodDbSecret) {
|
||||
if (!spec.platformDb) throw new Error(`secret ${name} is only supported for v0.3+ platform DB lanes`);
|
||||
if (key !== undefined && key !== spec.hwpodDbKey) throw new Error(`secret ${name} supports only key ${spec.hwpodDbKey}`);
|
||||
if (actionRaw === "ensure") {
|
||||
throw new Error(`secret ensure for ${name} on --lane ${lane} was removed after native platform DB migration; use status plus platform DB SecretRef rotation CLI when it exists`);
|
||||
}
|
||||
return {
|
||||
action: actionRaw,
|
||||
node,
|
||||
lane,
|
||||
name,
|
||||
key: key ?? spec.hwpodDbKey,
|
||||
preset: "hwpod-db",
|
||||
confirm,
|
||||
dryRun: true,
|
||||
timeoutSeconds: positiveIntegerOption(args, "--timeout-seconds", 240, 900),
|
||||
};
|
||||
}
|
||||
if (name !== spec.openFgaSecret) {
|
||||
throw new Error(`secret status/ensure supports --name ${spec.openFgaSecret}, ${spec.masterAdminApiKeySecret}, ${spec.cloudApiDbSecret}, or ${spec.codeAgentProviderSecret} for --lane ${lane}`);
|
||||
throw new Error(`secret status/ensure supports --name ${spec.openFgaSecret}, ${spec.masterAdminApiKeySecret}, ${spec.cloudApiDbSecret}, ${spec.hwpodDbSecret}, or ${spec.codeAgentProviderSecret} for --lane ${lane}`);
|
||||
}
|
||||
if (key !== undefined && key !== OPENFGA_AUTHN_KEY && key !== OPENFGA_DATASTORE_URI_KEY && key !== OPENFGA_POSTGRES_PASSWORD_KEY) {
|
||||
throw new Error(`secret ${name} supports keys ${OPENFGA_AUTHN_KEY}, ${OPENFGA_DATASTORE_URI_KEY}, and ${OPENFGA_POSTGRES_PASSWORD_KEY}`);
|
||||
@@ -332,6 +356,11 @@ function runtimeSecretSpec(input: { node: string; lane: string }): RuntimeSecret
|
||||
cloudApiDbUser: platformDb ? `hwlab_${input.lane}_app` : `hwlab_${input.lane}`,
|
||||
cloudApiDbHost: platformDb ? platformPostgresHost : legacyPostgresHost,
|
||||
cloudApiDeployment: "hwlab-cloud-api",
|
||||
hwpodDbSecret: `hwpod-${input.lane}-db`,
|
||||
hwpodDbKey: CLOUD_API_DB_KEY,
|
||||
hwpodDbName: `hwpod_${input.lane}`,
|
||||
hwpodDbUser: platformDb ? `hwpod_${input.lane}_app` : `hwpod_${input.lane}`,
|
||||
hwpodDbHost: platformDb ? platformPostgresHost : legacyPostgresHost,
|
||||
codeAgentProviderSecret: `${namespace}-code-agent-provider`,
|
||||
codeAgentProviderSourceNamespace: CODE_AGENT_PROVIDER_SOURCE_NAMESPACE,
|
||||
codeAgentProviderSourceSecret: CODE_AGENT_PROVIDER_SOURCE_SECRET,
|
||||
@@ -348,7 +377,7 @@ function runNodeSecret(options: NodeSecretOptions): Record<string, unknown> {
|
||||
? spec.platformDb ? platformDbSecretStatusScript(options, spec) : openFgaSecretScript(options, spec)
|
||||
: options.preset === "master-server-admin-api-key"
|
||||
? masterAdminApiKeySecretScript(options, spec)
|
||||
: options.preset === "cloud-api-db"
|
||||
: options.preset === "cloud-api-db" || options.preset === "hwpod-db"
|
||||
? spec.platformDb ? platformDbSecretStatusScript(options, spec) : cloudApiDbSecretScript(options, spec)
|
||||
: options.preset === "owned-postgres-cleanup"
|
||||
? ownedPostgresCleanupScript(options, spec)
|
||||
@@ -380,7 +409,7 @@ function nextSecretCommand(options: NodeSecretOptions, spec: RuntimeSecretSpec):
|
||||
if (options.action === "cleanup-owned-postgres") {
|
||||
return { ensure: `bun scripts/cli.ts hwlab nodes secret cleanup-owned-postgres --node ${options.node} --lane ${options.lane} --confirm` };
|
||||
}
|
||||
if (spec.platformDb && (options.preset === "cloud-api-db" || options.preset === "openfga")) {
|
||||
if (spec.platformDb && (options.preset === "cloud-api-db" || options.preset === "openfga" || options.preset === "hwpod-db")) {
|
||||
return {
|
||||
status: `bun scripts/cli.ts hwlab nodes secret status --node ${options.node} --lane ${options.lane} --name ${options.name}${options.key ? ` --key ${options.key}` : ""}`,
|
||||
controlPlaneStatus: `bun scripts/cli.ts hwlab nodes control-plane status --node ${options.node} --lane ${options.lane}`,
|
||||
@@ -769,12 +798,13 @@ function ownedPostgresCleanupScript(options: NodeSecretOptions, spec: RuntimeSec
|
||||
|
||||
function platformDbSecretStatusScript(options: NodeSecretOptions, spec: RuntimeSecretSpec): string {
|
||||
const isOpenFga = options.preset === "openfga";
|
||||
const isHwpodDb = options.preset === "hwpod-db";
|
||||
const platformEndpointSlice = `${spec.platformPostgresService}-host`;
|
||||
return [
|
||||
"set +e",
|
||||
`namespace=${shellQuote(spec.namespace)}`,
|
||||
`name=${shellQuote(isOpenFga ? spec.openFgaSecret : spec.cloudApiDbSecret)}`,
|
||||
`database_url_key=${shellQuote(isOpenFga ? OPENFGA_DATASTORE_URI_KEY : spec.cloudApiDbKey)}`,
|
||||
`name=${shellQuote(isOpenFga ? spec.openFgaSecret : isHwpodDb ? spec.hwpodDbSecret : spec.cloudApiDbSecret)}`,
|
||||
`database_url_key=${shellQuote(isOpenFga ? OPENFGA_DATASTORE_URI_KEY : isHwpodDb ? spec.hwpodDbKey : spec.cloudApiDbKey)}`,
|
||||
`authn_key=${shellQuote(OPENFGA_AUTHN_KEY)}`,
|
||||
`postgres_password_key=${shellQuote(OPENFGA_POSTGRES_PASSWORD_KEY)}`,
|
||||
`legacy_postgres_secret=${shellQuote(spec.postgresSecret)}`,
|
||||
@@ -782,9 +812,9 @@ function platformDbSecretStatusScript(options: NodeSecretOptions, spec: RuntimeS
|
||||
`platform_endpointslice=${shellQuote(platformEndpointSlice)}`,
|
||||
`platform_host=${shellQuote(spec.platformPostgresService)}`,
|
||||
`platform_host_fqdn=${shellQuote(spec.openFgaDbHost)}`,
|
||||
`db_name=${shellQuote(isOpenFga ? spec.openFgaDbName : spec.cloudApiDbName)}`,
|
||||
`db_user=${shellQuote(isOpenFga ? spec.openFgaDbUser : spec.cloudApiDbUser)}`,
|
||||
`db_host=${shellQuote(isOpenFga ? spec.openFgaDbHost : spec.cloudApiDbHost)}`,
|
||||
`db_name=${shellQuote(isOpenFga ? spec.openFgaDbName : isHwpodDb ? spec.hwpodDbName : spec.cloudApiDbName)}`,
|
||||
`db_user=${shellQuote(isOpenFga ? spec.openFgaDbUser : isHwpodDb ? spec.hwpodDbUser : spec.cloudApiDbUser)}`,
|
||||
`db_host=${shellQuote(isOpenFga ? spec.openFgaDbHost : isHwpodDb ? spec.hwpodDbHost : spec.cloudApiDbHost)}`,
|
||||
`selected_key=${shellQuote(options.key ?? "")}`,
|
||||
`preset=${shellQuote(options.preset)}`,
|
||||
"dry_run=true",
|
||||
@@ -1432,7 +1462,13 @@ function secretStatusFromText(text: string, commandOk: boolean, exitCode: number
|
||||
summary: healthy ? `${fields.secret || spec.codeAgentProviderSecret} has a usable provider key` : `${fields.secret || spec.codeAgentProviderSecret} missing provider keys`,
|
||||
};
|
||||
}
|
||||
if (fields.preset === "cloud-api-db") {
|
||||
if (fields.preset === "cloud-api-db" || fields.preset === "hwpod-db") {
|
||||
const hwpodDb = fields.preset === "hwpod-db";
|
||||
const expectedSecret = hwpodDb ? spec.hwpodDbSecret : spec.cloudApiDbSecret;
|
||||
const expectedKey = hwpodDb ? spec.hwpodDbKey : spec.cloudApiDbKey;
|
||||
const expectedDbName = hwpodDb ? spec.hwpodDbName : spec.cloudApiDbName;
|
||||
const expectedDbUser = hwpodDb ? spec.hwpodDbUser : spec.cloudApiDbUser;
|
||||
const expectedDbHost = hwpodDb ? spec.hwpodDbHost : spec.cloudApiDbHost;
|
||||
const beforeUrlBytes = numericField(fields.beforeDatabaseUrlBytes);
|
||||
const afterUrlBytes = numericField(fields.afterDatabaseUrlBytes);
|
||||
if (fields.platformDbMode === "true") {
|
||||
@@ -1449,9 +1485,9 @@ function secretStatusFromText(text: string, commandOk: boolean, exitCode: number
|
||||
return {
|
||||
ok: commandOk && healthy,
|
||||
namespace: fields.namespace || spec.namespace,
|
||||
secret: fields.secret || spec.cloudApiDbSecret,
|
||||
key: fields.key || spec.cloudApiDbKey,
|
||||
preset: "cloud-api-db",
|
||||
secret: fields.secret || expectedSecret,
|
||||
key: fields.key || expectedKey,
|
||||
preset: hwpodDb ? "hwpod-db" : "cloud-api-db",
|
||||
action: fields.action || null,
|
||||
dryRun: fields.dryRun === "true",
|
||||
mutation: fields.mutation === "true",
|
||||
@@ -1472,9 +1508,9 @@ function secretStatusFromText(text: string, commandOk: boolean, exitCode: number
|
||||
endpointSlice: fields.platformEndpointSlice || `${spec.platformPostgresService}-host`,
|
||||
endpointSliceExists: fields.platformEndpointSliceExists === "yes",
|
||||
},
|
||||
dbName: fields.dbName || spec.cloudApiDbName,
|
||||
dbUser: fields.dbUser || spec.cloudApiDbUser,
|
||||
dbHost: fields.dbHost || spec.cloudApiDbHost,
|
||||
dbName: fields.dbName || expectedDbName,
|
||||
dbUser: fields.dbUser || expectedDbUser,
|
||||
dbHost: fields.dbHost || expectedDbHost,
|
||||
dbHostMatchesPlatform: fields.dbHostMatchesPlatform === "yes",
|
||||
dbNameMatchesExpected: fields.dbNameMatchesExpected === "yes",
|
||||
dbUserMatchesExpected: fields.dbUserMatchesExpected === "yes",
|
||||
@@ -1482,8 +1518,24 @@ function secretStatusFromText(text: string, commandOk: boolean, exitCode: number
|
||||
stderr: commandOk ? "" : stderr.trim().slice(0, 2000),
|
||||
valuesRedacted: true,
|
||||
summary: healthy
|
||||
? `${fields.secret || spec.cloudApiDbSecret}/${fields.key || spec.cloudApiDbKey} points to ${fields.platformService || spec.platformPostgresService}`
|
||||
: `${fields.secret || spec.cloudApiDbSecret}/${fields.key || spec.cloudApiDbKey} is not aligned to platform DB`,
|
||||
? `${fields.secret || expectedSecret}/${fields.key || expectedKey} points to ${fields.platformService || spec.platformPostgresService}`
|
||||
: `${fields.secret || expectedSecret}/${fields.key || expectedKey} is not aligned to platform DB`,
|
||||
};
|
||||
}
|
||||
if (hwpodDb) {
|
||||
return {
|
||||
ok: false,
|
||||
namespace: fields.namespace || spec.namespace,
|
||||
secret: fields.secret || expectedSecret,
|
||||
key: fields.key || expectedKey,
|
||||
preset: "hwpod-db",
|
||||
action: fields.action || null,
|
||||
dryRun: fields.dryRun === "true",
|
||||
mutation: false,
|
||||
exitCode,
|
||||
stderr: commandOk ? "" : stderr.trim().slice(0, 2000),
|
||||
valuesRedacted: true,
|
||||
summary: "HWPOD DB Secret status is only supported for native platform DB lanes",
|
||||
};
|
||||
}
|
||||
const keysHealthy = fields.afterExists === "yes" &&
|
||||
@@ -1494,8 +1546,8 @@ function secretStatusFromText(text: string, commandOk: boolean, exitCode: number
|
||||
return {
|
||||
ok: commandOk && healthy,
|
||||
namespace: fields.namespace || spec.namespace,
|
||||
secret: fields.secret || spec.cloudApiDbSecret,
|
||||
key: fields.key || spec.cloudApiDbKey,
|
||||
secret: fields.secret || expectedSecret,
|
||||
key: fields.key || expectedKey,
|
||||
preset: "cloud-api-db",
|
||||
action: fields.action || null,
|
||||
dryRun: fields.dryRun === "true",
|
||||
@@ -1521,9 +1573,9 @@ function secretStatusFromText(text: string, commandOk: boolean, exitCode: number
|
||||
},
|
||||
postgresAdminSecretPresent: fields.postgresAdminSecretPresent === "yes",
|
||||
postgresSecret: fields.postgresSecret || spec.postgresSecret,
|
||||
dbName: fields.dbName || spec.cloudApiDbName,
|
||||
dbUser: fields.dbUser || spec.cloudApiDbUser,
|
||||
dbHost: fields.dbHost || spec.cloudApiDbHost,
|
||||
dbName: fields.dbName || expectedDbName,
|
||||
dbUser: fields.dbUser || expectedDbUser,
|
||||
dbHost: fields.dbHost || expectedDbHost,
|
||||
cloudApiDeployment: fields.cloudApiDeployment || spec.cloudApiDeployment,
|
||||
applyExitCode: numericField(fields.applyExitCode),
|
||||
dbEnsureExitCode: numericField(fields.dbEnsureExitCode),
|
||||
@@ -1532,7 +1584,7 @@ function secretStatusFromText(text: string, commandOk: boolean, exitCode: number
|
||||
exitCode,
|
||||
stderr: commandOk ? "" : stderr.trim().slice(0, 2000),
|
||||
valuesRedacted: true,
|
||||
summary: healthy ? `${fields.secret || spec.cloudApiDbSecret}/${fields.key || spec.cloudApiDbKey} exists and runtime database is present` : `${fields.secret || spec.cloudApiDbSecret}/${fields.key || spec.cloudApiDbKey} or runtime database missing`,
|
||||
summary: healthy ? `${fields.secret || expectedSecret}/${fields.key || expectedKey} exists and runtime database is present` : `${fields.secret || expectedSecret}/${fields.key || expectedKey} or runtime database missing`,
|
||||
};
|
||||
}
|
||||
const afterAuthnBytes = numericField(fields.afterAuthnBytes);
|
||||
|
||||
Reference in New Issue
Block a user