feat: verify server pull access before deployment

This commit is contained in:
NuklearRabbit
2026-07-29 16:17:54 +02:00
parent 430d40354b
commit ae6c41ff90
8 changed files with 196 additions and 16 deletions
+48
View File
@@ -80,6 +80,54 @@ test("server pull provisions a pinned repository-scoped key and records access m
assert.equal(result.remoteSha, "a".repeat(40));
});
test("server pull verification proves a repository-scoped read-only key and exact commit parity", async () => {
const sha = "c".repeat(40);
const profile = {
id: "profile-verify", provider: "ssh-unraid", serverId: "unraid", remoteFolder: "portfolio",
environment: "production", branch: "main", deploymentMode: "server-git", composeFiles: ["compose.yml"],
serverGitAccess: { deployKeyId: 17, keyFingerprint: "SHA256:key", hostFingerprint: "SHA256:host" },
};
const service = new UnraidDeploymentService({
store: {
getDeploymentProfile: () => profile,
getServer: () => ({ id: "unraid", name: "Unraid", basePath: "/mnt/user/appdata" }),
getDeploymentState: () => ({ liveSha: sha, containerRunning: true, healthy: true }),
},
ssh: { exec: async () => ({ stdout: `__FORGEFLOW_SERVER_GIT_PROBE__\nremoteSha=${sha}\nkeyFingerprint=SHA256:key\nhostFingerprint=SHA256:host\n` }) },
gitea: {
getBranch: async () => ({ commit: { id: sha } }),
listDeployKeys: async () => [{ id: 17, read_only: true }],
},
});
service.inspect = async () => ({ exists: true, composeFiles: ["compose.yml"], head: sha });
const report = await service.verifyServerGitProfile({ repository: { fullName: "Jens/Portfolio", sshUrl: "git@gitea.test:Jens/Portfolio.git" }, profileId: profile.id });
assert.equal(report.readiness, "Ready");
assert.equal(report.ready, true);
assert.equal(report.checks.find((check) => check.id === "deploy-key-scope").status, "pass");
});
test("server pull verification blocks a writable Gitea deploy key", async () => {
const sha = "d".repeat(40);
const profile = {
id: "profile-writable", provider: "ssh-unraid", serverId: "unraid", remoteFolder: "portfolio",
environment: "production", branch: "main", deploymentMode: "server-git", composeFiles: ["compose.yml"],
serverGitAccess: { deployKeyId: 18, keyFingerprint: "SHA256:key", hostFingerprint: "SHA256:host" },
};
const service = new UnraidDeploymentService({
store: {
getDeploymentProfile: () => profile,
getServer: () => ({ id: "unraid", name: "Unraid", basePath: "/mnt/user/appdata" }),
getDeploymentState: () => ({ liveSha: sha, containerRunning: true, healthy: true }),
},
ssh: { exec: async () => ({ stdout: `__FORGEFLOW_SERVER_GIT_PROBE__\nremoteSha=${sha}\nkeyFingerprint=SHA256:key\nhostFingerprint=SHA256:host\n` }) },
gitea: { getBranch: async () => ({ commit: { id: sha } }), listDeployKeys: async () => [{ id: 18, read_only: false }] },
});
service.inspect = async () => ({ exists: true, composeFiles: ["compose.yml"], head: sha });
const report = await service.verifyServerGitProfile({ repository: { fullName: "Jens/Portfolio", sshUrl: "git@gitea.test:Jens/Portfolio.git" }, profileId: profile.id });
assert.equal(report.readiness, "Access failed");
assert.equal(report.ready, false);
});
test("server workload inventory links running containers to exact Gitea checkouts", () => {
const b64 = (value) => Buffer.from(value).toString("base64");
const inspect = JSON.stringify([