fix: harden deployment discovery and preflight
ForgeFlow quality gate / quality (push) Canceled after 0s
ForgeFlow quality gate / quality (push) Canceled after 0s
This commit is contained in:
@@ -115,8 +115,12 @@ test("repository changes, Git tools and Git Validator complete their primary flo
|
||||
|
||||
test("every long application surface retains a working vertical scroll owner", async ({ page }) => {
|
||||
for (const view of ["overview", "deployments", "diagnostics", "settings"]) {
|
||||
await page.locator(`.nav-button[data-view="${view}"]`).click();
|
||||
await assertScrollableWhenOverflowing(page, ".main-canvas");
|
||||
await test.step(`${view} view scrolls`, async () => {
|
||||
const navigation = page.locator(`.nav-button[data-view="${view}"]`);
|
||||
await navigation.click();
|
||||
await expect(navigation).toHaveClass(/active/);
|
||||
await assertScrollableWhenOverflowing(page, ".main-canvas");
|
||||
});
|
||||
}
|
||||
await page.locator('[data-action="select-repo"]').first().click();
|
||||
for (const tab of ["history", "deployments", "gittools", "validator", "settings"]) {
|
||||
|
||||
@@ -10,6 +10,13 @@ async function ipcSource() {
|
||||
return (await Promise.all(["ipc.cjs", "ipc/repository-handlers.cjs", "ipc/deployment-handlers.cjs", "ipc/operations-handlers.cjs"].map((file) => readFile(new URL(`../src/main/${file}`, import.meta.url), "utf8")))).join("\n");
|
||||
}
|
||||
|
||||
test("desktop shell serializes ForgeFlow to one configuration writer", async () => {
|
||||
const main = await readFile(new URL("../main.cjs", import.meta.url), "utf8");
|
||||
assert.match(main, /requestSingleInstanceLock\(\)/);
|
||||
assert.match(main, /second-instance/);
|
||||
assert.match(main, /showMainWindow\(\)/);
|
||||
});
|
||||
|
||||
test("changed file list has an independently scrollable bounded layout", async () => {
|
||||
const css = await readFile(
|
||||
new URL("../src/renderer/styles.css", import.meta.url),
|
||||
|
||||
@@ -141,4 +141,10 @@ test('legacy container sanitizer applies safe defaults to partial Docker inspect
|
||||
'tech.itworx.forgeflow.branch': '', 'net.unraid.docker.webui': '', 'net.unraid.docker.icon': '', 'net.unraid.docker.shell': '', 'net.unraid.docker.managed': '',
|
||||
}, ports: {}, mounts: [], networks: {}, restartPolicy: '',
|
||||
});
|
||||
assert.equal(sanitizeLegacyContainer({
|
||||
Id: 'no-healthcheck',
|
||||
Name: '/NoHealthcheck',
|
||||
State: { Running: true, Status: 'running' },
|
||||
Config: { Image: 'example/no-healthcheck:latest', Labels: null },
|
||||
}).health, null);
|
||||
});
|
||||
|
||||
@@ -112,6 +112,33 @@ test("server pull verification proves a repository-scoped read-only key and exac
|
||||
assert.equal(report.checks.find((check) => check.id === "deploy-key-scope").status, "pass");
|
||||
});
|
||||
|
||||
test("server pull remains deploy-ready when only live runtime evidence is incomplete", async () => {
|
||||
const sha = "c".repeat(40);
|
||||
const profile = {
|
||||
id: "profile-runtime-incomplete", 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: () => ({ containerRunning: true, healthy: null }),
|
||||
},
|
||||
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: null });
|
||||
const report = await service.verifyServerGitProfile({ repository: { fullName: "Jens/Portfolio", sshUrl: "git@gitea.test:Jens/Portfolio.git" }, profileId: profile.id });
|
||||
assert.equal(report.deployReady, true);
|
||||
assert.equal(report.ready, true);
|
||||
assert.equal(report.readiness, "Deploy-ready; runtime verification incomplete");
|
||||
assert.deepEqual(report.deploymentBlockers, []);
|
||||
});
|
||||
|
||||
test("server pull verification blocks a writable Gitea deploy key", async () => {
|
||||
const sha = "d".repeat(40);
|
||||
const profile = {
|
||||
@@ -1071,6 +1098,8 @@ test("inventory scan uses only configured roots and reports partial find failure
|
||||
assert.match(script, /-name 'scratch'/);
|
||||
assert.match(script, /Inventory scan partially failed/);
|
||||
assert.match(script, /2>"\$scan_error" \|\| true/);
|
||||
assert.match(script, /docker inspect "\$container_id"/);
|
||||
assert.doesNotMatch(script, /docker inspect --format/);
|
||||
assert.doesNotMatch(script, /add_scan_root \/mnt\/cache\/appdata/);
|
||||
});
|
||||
|
||||
@@ -1294,7 +1323,10 @@ test("server-pull preflight resolves Gitea SHA and reports every degraded capabi
|
||||
},
|
||||
git: { status: async () => ({ root: "/local", clean: false, counts: { changed: 3 }, branch: { head: "main" } }) },
|
||||
ssh: { test: async () => ({ capabilities: { docker: true, dockerReady: false, compose: false, git: false, tar: true, checksum: false, baseWritable: false } }) },
|
||||
gitea: { getBranch: async () => ({ commit: { sha } }) },
|
||||
gitea: {
|
||||
getBranch: async () => ({ commit: { sha } }),
|
||||
repositoryFileExists: async ({ filePath, ref }) => ref === sha && filePath === "compose.yml",
|
||||
},
|
||||
sourcePath: process.cwd()
|
||||
});
|
||||
service.probeServerGitAccess = async () => ({ ready: false, error: "deploy key missing", remoteSha: null });
|
||||
@@ -1308,6 +1340,8 @@ test("server-pull preflight resolves Gitea SHA and reports every degraded capabi
|
||||
assert.equal(result.sha, sha);
|
||||
assert.equal(byId("local-branch").status, "warning");
|
||||
assert.equal(byId("local-clean").status, "warning");
|
||||
assert.equal(byId("gitea-deployment-files").status, "fail");
|
||||
assert.match(byId("gitea-deployment-files").detail, /compose\.prod\.yml/);
|
||||
assert.equal(byId("docker-runtime").status, "fail");
|
||||
assert.match(byId("docker-runtime").detail, /cannot query/i);
|
||||
assert.equal(byId("compose-command").status, "fail");
|
||||
|
||||
Reference in New Issue
Block a user