diff --git a/scripts/native/cicd/publish-platform-infra-temporal-gitops.ts b/scripts/native/cicd/publish-platform-infra-temporal-gitops.ts index 7536b4c3..4a233c3d 100644 --- a/scripts/native/cicd/publish-platform-infra-temporal-gitops.ts +++ b/scripts/native/cicd/publish-platform-infra-temporal-gitops.ts @@ -28,9 +28,10 @@ const temporal = readTemporalConfig(); if (!temporal.delivery.enabled) throw new Error("config/platform-infra/temporal.yaml#delivery.enabled must be true"); const target = temporal.targets.find((item) => item.id === temporal.defaults.targetId && item.enabled); if (target === undefined) throw new Error("Temporal default delivery target is not enabled"); -const manifest = renderTemporalGitOpsManifest(temporal, target); +const manifest = renderTemporalGitOpsManifest(temporal, target, sourceCommit); if (manifest.includes("kind: Secret")) throw new Error("GitOps manifest must not contain Secret payloads"); if (!manifest.includes("kind: Deployment") || !manifest.includes("kind: Service")) throw new Error("Temporal GitOps renderer did not produce workloads"); +if (!manifest.includes(`unidesk.ai/source-commit: ${sourceCommit}`)) throw new Error("Temporal GitOps renderer did not preserve exact source identity"); if (dryRun) { console.log(JSON.stringify({ ok: true, mutation: false, mode: "dry-run", sourceCommit, branch: temporal.delivery.gitops.branch, manifestPath: temporal.delivery.gitops.manifestPath, objectCount: manifest.split("\n---\n").length, secretValuesPrinted: false, valuesPrinted: false })); process.exit(0); diff --git a/scripts/src/platform-infra-temporal.ts b/scripts/src/platform-infra-temporal.ts index 270cb9ad..cde2f20c 100644 --- a/scripts/src/platform-infra-temporal.ts +++ b/scripts/src/platform-infra-temporal.ts @@ -240,11 +240,18 @@ async function observe( }; } -export function renderTemporalGitOpsManifest(temporal: TemporalConfig, target: TemporalTarget): string { - return renderManifest(temporal, target, null, false); +export function renderTemporalGitOpsManifest(temporal: TemporalConfig, target: TemporalTarget, sourceCommit: string): string { + if (!/^[0-9a-f]{40}$/u.test(sourceCommit)) throw new Error("sourceCommit must be a full Git commit SHA"); + return renderManifest(temporal, target, null, false, sourceCommit); } -function renderManifest(temporal: TemporalConfig, target: TemporalTarget, material: DatabaseMaterial | null, includeDatabaseSecret = true): string { +function renderManifest( + temporal: TemporalConfig, + target: TemporalTarget, + material: DatabaseMaterial | null, + includeDatabaseSecret = true, + sourceCommit: string | null = null, +): string { const server = temporal.runtime.server; const ui = temporal.runtime.ui; const secretData = material === null @@ -252,6 +259,7 @@ function renderManifest(temporal: TemporalConfig, target: TemporalTarget, materi : material; const encoded = (value: string) => Buffer.from(value, "utf8").toString("base64"); const namespace = target.namespace; + const sourceIdentityLabel = sourceCommit === null ? "" : `\n unidesk.ai/source-commit: ${sourceCommit}`; const logicalNamespaceCommands = temporal.runtime.logicalNamespaces.map((item) => ` if ! temporal operator namespace describe --address ${server.serviceName}:${server.frontendPort} --namespace ${item.name} >/dev/null 2>&1; then temporal operator namespace create --address ${server.serviceName}:${server.frontendPort} --namespace ${item.name} --retention ${item.retention} @@ -308,7 +316,7 @@ spec: metadata: labels: app.kubernetes.io/name: temporal - app.kubernetes.io/part-of: temporal + app.kubernetes.io/part-of: temporal${sourceIdentityLabel} spec: enableServiceLinks: ${server.enableServiceLinks} shareProcessNamespace: ${server.shareProcessNamespace} @@ -395,7 +403,7 @@ spec: metadata: labels: app.kubernetes.io/name: temporal-ui - app.kubernetes.io/part-of: temporal + app.kubernetes.io/part-of: temporal${sourceIdentityLabel} spec: enableServiceLinks: ${ui.enableServiceLinks} containers: @@ -485,7 +493,7 @@ spec: metadata: labels: app.kubernetes.io/name: temporal-logical-namespaces - app.kubernetes.io/part-of: temporal + app.kubernetes.io/part-of: temporal${sourceIdentityLabel} spec: restartPolicy: Never containers: