mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-28 14:15:24 +00:00
fix(hosts): normalize imported jump host references (#1470)
* fix(hosts): normalize imported jump host references * fix(ci): build plugin SDK before dependent checks * fix(mysql): keep plugin settings scope indexes within limits * test(mysql): refresh reviewed plugin upgrade SQL
This commit is contained in:
1 parent
710f545e34
commit
ec982aadb5
2 files changed
+63
-40
No files matched your search
@@ -1,5 +1,11 @@
|
||||
import { normalizeImportedHost } from "./host-normalizers.js";
|
||||
|
||||
function jumpHostId(value: unknown): unknown {
|
||||
return typeof value === "string" && /^\d+$/.test(value)
|
||||
? Number(value)
|
||||
: value;
|
||||
}
|
||||
|
||||
export function prepareHostImports(input: Record<string, unknown>[]) {
|
||||
const hosts = input.map((value, index) => ({
|
||||
host: normalizeImportedHost(value),
|
||||
@@ -27,7 +33,7 @@ export function prepareHostImports(input: Record<string, unknown>[]) {
|
||||
if (!Array.isArray(jumps))
|
||||
throw new Error(`Host ${entry.index + 1}: jumpHosts must be an array`);
|
||||
for (const jump of jumps) {
|
||||
const dependency = byId.get(jump?.hostId);
|
||||
const dependency = byId.get(jumpHostId(jump?.hostId));
|
||||
if (!dependency)
|
||||
throw new Error(
|
||||
`Host ${entry.index + 1}: jump host ${jump?.hostId} is missing from the export. Re-export and include all jump hosts.`,
|
||||
@@ -48,7 +54,7 @@ export function remapImportedJumpHosts(
|
||||
) {
|
||||
if (!Array.isArray(jumps)) return null;
|
||||
return jumps.map((jump) => {
|
||||
const hostId = importedIds.get(jump.hostId);
|
||||
const hostId = importedIds.get(jumpHostId(jump.hostId));
|
||||
if (hostId === undefined)
|
||||
throw new Error(`Jump host ${jump.hostId} failed to import`);
|
||||
return { hostId };
|
||||
|
||||
@@ -103,49 +103,66 @@ async function importHosts(
|
||||
return res;
|
||||
}
|
||||
|
||||
it("imports forward jump references first and replaces source IDs with destination IDs", async () => {
|
||||
mocks.create
|
||||
.mockResolvedValueOnce({ id: 501 })
|
||||
.mockResolvedValueOnce({ id: 502 });
|
||||
const raw = {
|
||||
hosts: [
|
||||
{ ...host, exportId: 10, jumpHosts: [{ hostId: 20 }] },
|
||||
{ ...host, ip: "192.0.2.2", exportId: 20 },
|
||||
],
|
||||
};
|
||||
const payload = buildExportPayload(raw, null, new Set(["jumpHosts"]), false);
|
||||
const res = await importHosts(payload.hosts);
|
||||
expect(res.json).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ success: 2, failed: 0 }),
|
||||
);
|
||||
expect(mocks.create.mock.calls[0][1].ip).toBe("192.0.2.2");
|
||||
expect(JSON.parse(mocks.create.mock.calls[1][1].jumpHosts)).toEqual([
|
||||
{ hostId: 501 },
|
||||
]);
|
||||
expect(mocks.create.mock.calls[1][1]).not.toHaveProperty("exportId");
|
||||
expect(mocks.create.mock.calls[1][1]).not.toHaveProperty("id");
|
||||
});
|
||||
it.each([20, "20"])(
|
||||
"imports forward jump reference %j and replaces source IDs with destination IDs",
|
||||
async (jumpId) => {
|
||||
mocks.create
|
||||
.mockResolvedValueOnce({ id: 501 })
|
||||
.mockResolvedValueOnce({ id: 502 });
|
||||
const raw = {
|
||||
hosts: [
|
||||
{ ...host, exportId: 10, jumpHosts: [{ hostId: jumpId }] },
|
||||
{ ...host, ip: "192.0.2.2", exportId: 20 },
|
||||
],
|
||||
};
|
||||
const payload = buildExportPayload(
|
||||
raw,
|
||||
null,
|
||||
new Set(["jumpHosts"]),
|
||||
false,
|
||||
);
|
||||
const res = await importHosts(payload.hosts);
|
||||
expect(res.json).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ success: 2, failed: 0 }),
|
||||
);
|
||||
expect(mocks.create.mock.calls[0][1].ip).toBe("192.0.2.2");
|
||||
expect(JSON.parse(mocks.create.mock.calls[1][1].jumpHosts)).toEqual([
|
||||
{ hostId: 501 },
|
||||
]);
|
||||
expect(mocks.create.mock.calls[1][1]).not.toHaveProperty("exportId");
|
||||
expect(mocks.create.mock.calls[1][1]).not.toHaveProperty("id");
|
||||
},
|
||||
);
|
||||
|
||||
it("maps overwritten jump hosts to their existing destination ID", async () => {
|
||||
mocks.list.mockResolvedValue([{ ...host, ip: "192.0.2.2", id: 801 }]);
|
||||
const res = await importHosts(
|
||||
[
|
||||
{ ...host, exportId: 10, jumpHosts: [{ hostId: 20 }] },
|
||||
{ ...host, ip: "192.0.2.2", exportId: 20 },
|
||||
],
|
||||
true,
|
||||
);
|
||||
expect(res.json).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ success: 1, updated: 1, failed: 0 }),
|
||||
);
|
||||
expect(JSON.parse(mocks.create.mock.calls[0][1].jumpHosts)).toEqual([
|
||||
{ hostId: 801 },
|
||||
]);
|
||||
});
|
||||
it.each([20, "20"])(
|
||||
"maps overwritten jump reference %j to its existing destination ID",
|
||||
async (jumpId) => {
|
||||
mocks.list.mockResolvedValue([{ ...host, ip: "192.0.2.2", id: 801 }]);
|
||||
const res = await importHosts(
|
||||
[
|
||||
{ ...host, exportId: 10, jumpHosts: [{ hostId: jumpId }] },
|
||||
{ ...host, ip: "192.0.2.2", exportId: 20 },
|
||||
],
|
||||
true,
|
||||
);
|
||||
expect(res.json).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ success: 1, updated: 1, failed: 0 }),
|
||||
);
|
||||
expect(JSON.parse(mocks.create.mock.calls[0][1].jumpHosts)).toEqual([
|
||||
{ hostId: 801 },
|
||||
]);
|
||||
},
|
||||
);
|
||||
|
||||
it.each([
|
||||
[{ ...host, jumpHosts: [{ hostId: 20 }] }],
|
||||
[{ ...host, jumpHosts: [{ hostId: "20" }] }],
|
||||
[{ ...host, exportId: 10, jumpHosts: [{ hostId: 10 }] }],
|
||||
[{ ...host, exportId: 10, jumpHosts: [{ hostId: "10" }] }],
|
||||
[
|
||||
{ ...host, exportId: 10, jumpHosts: [{ hostId: "20oops" }] },
|
||||
{ ...host, exportId: 20 },
|
||||
],
|
||||
[
|
||||
{ ...host, exportId: 10 },
|
||||
{ ...host, exportId: 10 },
|
||||
|
||||
Reference in new issue
Block a user