feat: add transactional deploy key lifecycle

This commit is contained in:
NuklearRabbit committed 2026-07-29 17:20:31 +02:00
1 parent 64ca267384
commit 6b93391a9b
10 files changed
+563 -39

No files matched your search

+25
View File
@@ -1606,6 +1606,31 @@
],
};
},
async deployKeyInventory(repository, profileId) {
const repo = repositories.find((item) => item.fullName === repository.fullName);
const profile = repo?.deploymentProfiles.find((item) => item.id === profileId);
return { repository: repo.fullName, profileId, server: { id: profile.serverId, name: "Unraid" }, configuredKey: { id: profile.serverGitAccess?.deployKeyId || 17, readOnly: true }, serverKey: { privateKeyPresent: true, fingerprint: profile.serverGitAccess?.keyFingerprint || "SHA256:demo" }, stale: false, orphaned: [], shared: [], conflicts: [], ready: true, checkedAt: iso() };
},
async planDeployKeyRotation(repository, profileId) {
const evidence = await this.deployKeyInventory(repository, profileId);
return { id: `rotation-${profileId}`, operation: "rotate-deploy-key", impact: ["Generate a new server-side key", "Verify read-only access", "Switch atomically", "Revoke the previous key"], recovery: "Previous access remains recoverable until verification succeeds.", evidence };
},
async applyDeployKeyRotation(repository, profileId) {
const repo = repositories.find((item) => item.fullName === repository.fullName); const profile = repo.deploymentProfiles.find((item) => item.id === profileId);
profile.serverGitAccess = { ...profile.serverGitAccess, configured: true, deployKeyId: 18, keyFingerprint: "SHA256:rotated", rotatedAt: iso() }; syncState(); return { profile: clone(profile), state: clone(state) };
},
async planDeployKeyRevocation(repository, profileId) {
const evidence = await this.deployKeyInventory(repository, profileId);
return { id: `revocation-${profileId}`, operation: "revoke-deploy-key", impact: ["Remove the repository key", "Disable server pull", "Preserve recovery material"], containersUnaffected: true, evidence };
},
async applyDeployKeyRevocation(repository, profileId) {
const repo = repositories.find((item) => item.fullName === repository.fullName); const profile = repo.deploymentProfiles.find((item) => item.id === profileId);
profile.deploymentMode = "monitor-only"; profile.serverGitAccess = { ...profile.serverGitAccess, configured: false, revokedAt: iso(), recoveryAvailable: true }; syncState(); return { profile: clone(profile), state: clone(state) };
},
async restoreDeployKey(repository, profileId) {
const repo = repositories.find((item) => item.fullName === repository.fullName); const profile = repo.deploymentProfiles.find((item) => item.id === profileId);
profile.deploymentMode = "server-git"; profile.serverGitAccess = { ...profile.serverGitAccess, configured: true, deployKeyId: 19, keyFingerprint: "SHA256:restored", restoredAt: iso() }; syncState(); return { profile: clone(profile), state: clone(state), proof: { ready: true } };
},
async refreshOperations(operationId = null) {
await wait(300);
if (operationId) {