feat: add github-backed decision storage

This commit is contained in:
Codex
2026-07-09 18:42:45 +02:00
parent 50a166a2ce
commit 6fc459e1fb
6 changed files with 629 additions and 12 deletions
@@ -182,7 +182,59 @@ function readDecisionCenterDatabase(decision) {
};
}
function readFileSource(sourceRef, path) {
const sourcePath = resolve(required(sourceRef.path, `${path}.path`));
const value = readFileSync(sourcePath, "utf8");
if (value.length === 0) throw new Error(`missing file content in ${sourcePath}`);
return {
sourcePath,
sourceRefPath: required(sourceRef.path, `${path}.path`),
value,
fingerprint: sha(value),
};
}
function readDecisionCenterStorage(decision) {
if (decision === null) return null;
const storage = optionalRecord(decision.storage, "services.decisionCenter.storage");
if (storage === null) return null;
const primary = required(storage.primary, "services.decisionCenter.storage.primary");
if (primary !== "postgres" && primary !== "github-repo") throw new Error("services.decisionCenter.storage.primary must be postgres or github-repo");
const github = primary === "github-repo" ? record(storage.github, "services.decisionCenter.storage.github") : null;
if (github === null) return { primary };
const ssh = record(github.ssh, "services.decisionCenter.storage.github.ssh");
const privateKey = record(ssh.privateKey, "services.decisionCenter.storage.github.ssh.privateKey");
const knownHosts = record(ssh.knownHosts, "services.decisionCenter.storage.github.ssh.knownHosts");
const privateKeySource = readFileSource(record(privateKey.sourceRef, "services.decisionCenter.storage.github.ssh.privateKey.sourceRef"), "services.decisionCenter.storage.github.ssh.privateKey.sourceRef");
const knownHostsSource = readFileSource(record(knownHosts.sourceRef, "services.decisionCenter.storage.github.ssh.knownHosts.sourceRef"), "services.decisionCenter.storage.github.ssh.knownHosts.sourceRef");
return {
primary,
github: {
repo: required(github.repo, "services.decisionCenter.storage.github.repo"),
sshUrl: required(github.sshUrl, "services.decisionCenter.storage.github.sshUrl"),
branch: required(github.branch, "services.decisionCenter.storage.github.branch"),
basePath: required(github.basePath, "services.decisionCenter.storage.github.basePath"),
worktreePath: required(github.worktreePath, "services.decisionCenter.storage.github.worktreePath"),
commitMessagePrefix: required(github.commitMessagePrefix, "services.decisionCenter.storage.github.commitMessagePrefix"),
author: {
name: required(record(github.author, "services.decisionCenter.storage.github.author").name, "services.decisionCenter.storage.github.author.name"),
email: required(record(github.author, "services.decisionCenter.storage.github.author").email, "services.decisionCenter.storage.github.author.email"),
},
ssh: {
secretName: required(ssh.secretName, "services.decisionCenter.storage.github.ssh.secretName"),
mountPath: required(ssh.mountPath, "services.decisionCenter.storage.github.ssh.mountPath"),
privateKeyKey: required(privateKey.secretKey, "services.decisionCenter.storage.github.ssh.privateKey.secretKey"),
knownHostsKey: required(knownHosts.secretKey, "services.decisionCenter.storage.github.ssh.knownHosts.secretKey"),
privateKeySource,
knownHostsSource,
fingerprint: sha(`${privateKeySource.fingerprint}\n${knownHostsSource.fingerprint}`),
},
},
};
}
const decisionCenterDatabase = readDecisionCenterDatabase(decisionCenter);
const decisionCenterStorage = readDecisionCenterStorage(decisionCenter);
const effectiveMicroservicesJson = decisionCenter === null
? required(runtimeConfig.microservicesJson, "runtimeConfig.microservicesJson")
: JSON.stringify([
@@ -295,6 +347,24 @@ type: Opaque
stringData:
${decisionCenterDatabase.secretKey}: ${yamlScalar(decisionCenterDatabase.value)}`);
}
if (decisionCenterStorage?.github !== undefined) {
docs.push(`apiVersion: v1
kind: Secret
metadata:
name: ${decisionCenterStorage.github.ssh.secretName}
namespace: ${namespace}
labels:
${indent(labels(config), 4)}
app.kubernetes.io/name: decision-center
annotations:
unidesk.ai/private-key-source-ref: ${yamlScalar(decisionCenterStorage.github.ssh.privateKeySource.sourceRefPath)}
unidesk.ai/known-hosts-source-ref: ${yamlScalar(decisionCenterStorage.github.ssh.knownHostsSource.sourceRefPath)}
unidesk.ai/fingerprint: ${yamlScalar(decisionCenterStorage.github.ssh.fingerprint)}
type: Opaque
stringData:
${decisionCenterStorage.github.ssh.privateKeyKey}: ${yamlScalar(decisionCenterStorage.github.ssh.privateKeySource.value)}
${decisionCenterStorage.github.ssh.knownHostsKey}: ${yamlScalar(decisionCenterStorage.github.ssh.knownHostsSource.value)}`);
}
if (databaseMode === "k8s-postgres") {
docs.push(`apiVersion: v1
kind: PersistentVolumeClaim
@@ -552,6 +622,7 @@ spec:
app.kubernetes.io/part-of: unidesk
annotations:
unidesk.ai/secret-fingerprint: ${yamlScalar(decisionCenterDatabase?.fingerprint ?? "")}
unidesk.ai/storage-secret-fingerprint: ${yamlScalar(decisionCenterStorage?.github?.ssh.fingerprint ?? "")}
unidesk.ai/runtime-config-fingerprint: ${yamlScalar(runtimeConfigFingerprint)}
spec:
initContainers:
@@ -594,9 +665,30 @@ spec:
value: ${yamlScalar(required(runtime.commit, "runtime.commit"))}
- name: LOG_FILE
value: ${yamlScalar(required(decisionCenter.logFile, "services.decisionCenter.logFile"))}
- name: DECISION_CENTER_STORAGE_PRIMARY
value: ${yamlScalar(decisionCenterStorage?.primary ?? "postgres")}
${decisionCenterStorage?.github !== undefined ? indent(`- name: DECISION_CENTER_GIT_REPO_SSH_URL
value: ${yamlScalar(decisionCenterStorage.github.sshUrl)}
- name: DECISION_CENTER_GIT_BRANCH
value: ${yamlScalar(decisionCenterStorage.github.branch)}
- name: DECISION_CENTER_GIT_BASE_PATH
value: ${yamlScalar(decisionCenterStorage.github.basePath)}
- name: DECISION_CENTER_GIT_WORKTREE
value: ${yamlScalar(decisionCenterStorage.github.worktreePath)}
- name: DECISION_CENTER_GIT_AUTHOR_NAME
value: ${yamlScalar(decisionCenterStorage.github.author.name)}
- name: DECISION_CENTER_GIT_AUTHOR_EMAIL
value: ${yamlScalar(decisionCenterStorage.github.author.email)}
- name: DECISION_CENTER_GIT_COMMIT_PREFIX
value: ${yamlScalar(decisionCenterStorage.github.commitMessagePrefix)}
- name: GIT_SSH_COMMAND
value: ${yamlScalar(`ssh -i ${decisionCenterStorage.github.ssh.mountPath}/${decisionCenterStorage.github.ssh.privateKeyKey} -o UserKnownHostsFile=${decisionCenterStorage.github.ssh.mountPath}/${decisionCenterStorage.github.ssh.knownHostsKey} -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes`)}`, 12) : ""}
volumeMounts:
- name: logs
mountPath: /var/log/unidesk
${decisionCenterStorage?.github !== undefined ? indent(`- name: github-ssh
mountPath: ${yamlScalar(decisionCenterStorage.github.ssh.mountPath)}
readOnly: true`, 12) : ""}
readinessProbe:
httpGet:
path: ${required(decisionCenter.healthPath, "services.decisionCenter.healthPath")}
@@ -622,6 +714,13 @@ ${indent(resourceBlock(decisionCenter.resources), 10)}
volumes:
- name: logs
emptyDir: {}`);
if (decisionCenterStorage?.github !== undefined) {
docs[docs.length - 1] += `
- name: github-ssh
secret:
secretName: ${decisionCenterStorage.github.ssh.secretName}
defaultMode: 0400`;
}
}
docs.push(`apiVersion: v1
kind: Service