mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-30 23:25:24 +00:00
v26.10.5 (#1710)
* feat: add an auto or fixed columns picker to card grids * feat: add safe mode that only runs layout and theme plugins * docs: add simple layout to plugin table * fix: ask for local network access in the macOS app * feat: allow plugin registries on listed private hosts (#1705) * chore: add private registry hosts to the changelog * feat: use the proxy for plugin registry downloads * fix: allow changing connection origin on shared hosts * chore: update translations and plugin pins * chore: lint, format, and bump version to 26.10.5 --------- Co-authored-by: Lukas <80832688+0skater0@users.noreply.github.com>
This commit is contained in:
1 parent
7b7b17e31f
commit
96b8520fb4
96 files changed
+1885
-474
No files matched your search
@@ -8,10 +8,23 @@ import * as tar from "tar";
|
||||
const fetchMock = vi.hoisted(() => vi.fn());
|
||||
const testKey = vi.hoisted(() => ({ value: null as null | object }));
|
||||
|
||||
vi.mock("../../utils/safe-outbound-fetch.js", () => ({
|
||||
vi.mock("../../utils/safe-outbound-fetch.js", async (importOriginal) => ({
|
||||
...(await importOriginal<
|
||||
typeof import("../../utils/safe-outbound-fetch.js")
|
||||
>()),
|
||||
safeOutboundFetch: fetchMock,
|
||||
}));
|
||||
|
||||
const proxyMock = vi.hoisted(() => ({
|
||||
on: false,
|
||||
fetch: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("../../utils/proxy-agent.js", () => ({
|
||||
getProxyAgent: () => (proxyMock.on ? {} : undefined),
|
||||
fetchWithProxy: proxyMock.fetch,
|
||||
}));
|
||||
|
||||
vi.mock("../../utils/app-version.js", () => ({
|
||||
getLocalVersion: () => "26.10.3",
|
||||
}));
|
||||
@@ -43,9 +56,11 @@ vi.mock("../../plugins/trust.js", async (importOriginal) => {
|
||||
import {
|
||||
communitySource,
|
||||
downloadRelease,
|
||||
fetchIndexAt,
|
||||
fetchRegistryIndex,
|
||||
fetchRegistryStats,
|
||||
findRelease,
|
||||
getRegistryPrivateHosts,
|
||||
latestOnChannel,
|
||||
getStatsUrl,
|
||||
canRunRelease,
|
||||
@@ -409,6 +424,91 @@ describe("fetchRegistryIndex", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("registry fetches with a proxy", () => {
|
||||
afterEach(() => {
|
||||
proxyMock.on = false;
|
||||
proxyMock.fetch.mockReset();
|
||||
});
|
||||
|
||||
it("goes through the proxy when one is configured", async () => {
|
||||
proxyMock.on = true;
|
||||
proxyMock.fetch.mockResolvedValueOnce(
|
||||
response(JSON.stringify({ plugins: [] })),
|
||||
);
|
||||
await fetchIndexAt("https://registry.example/index.json");
|
||||
expect(proxyMock.fetch).toHaveBeenCalledTimes(1);
|
||||
expect(fetchMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("still refuses a private address typed in as a literal", async () => {
|
||||
proxyMock.on = true;
|
||||
await expect(fetchIndexAt("https://127.0.0.1/index.json")).rejects.toThrow(
|
||||
"Private destinations are not allowed",
|
||||
);
|
||||
expect(proxyMock.fetch).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("private registry hosts", () => {
|
||||
afterEach(() => {
|
||||
delete process.env.TERMIX_PLUGIN_REGISTRY_PRIVATE_HOSTS;
|
||||
});
|
||||
|
||||
it("reads a comma separated list of host names", () => {
|
||||
process.env.TERMIX_PLUGIN_REGISTRY_PRIVATE_HOSTS =
|
||||
" GitLab.lan ,, 192.168.1.5 ";
|
||||
expect(getRegistryPrivateHosts()).toEqual(["gitlab.lan", "192.168.1.5"]);
|
||||
delete process.env.TERMIX_PLUGIN_REGISTRY_PRIVATE_HOSTS;
|
||||
expect(getRegistryPrivateHosts()).toEqual([]);
|
||||
});
|
||||
|
||||
it("brings each entry into the form the fetch compares against", () => {
|
||||
process.env.TERMIX_PLUGIN_REGISTRY_PRIVATE_HOSTS =
|
||||
"GitLab.LAN,[FD00::0001],fd00::2,bücher.lan";
|
||||
expect(getRegistryPrivateHosts()).toEqual([
|
||||
"gitlab.lan",
|
||||
"fd00::1",
|
||||
"fd00::2",
|
||||
"xn--bcher-kva.lan",
|
||||
]);
|
||||
});
|
||||
|
||||
it("drops entries with more than a host", () => {
|
||||
process.env.TERMIX_PLUGIN_REGISTRY_PRIVATE_HOSTS =
|
||||
"gitlab.lan:8443,https://git.lan,[fd00::1]:80,nas.lan";
|
||||
expect(getRegistryPrivateHosts()).toEqual(["nas.lan"]);
|
||||
});
|
||||
|
||||
it("allows the listed hosts on every hop", async () => {
|
||||
process.env.TERMIX_PLUGIN_REGISTRY_PRIVATE_HOSTS = "gitlab.lan";
|
||||
fetchMock
|
||||
.mockResolvedValueOnce(
|
||||
response("", 302, { location: "https://gitlab.lan/raw/index.json" }),
|
||||
)
|
||||
.mockResolvedValueOnce(response(JSON.stringify({ plugins: [] })));
|
||||
await fetchIndexAt("https://gitlab.lan/index.json");
|
||||
expect(fetchMock.mock.calls.map((call) => call[2])).toEqual([
|
||||
["gitlab.lan"],
|
||||
["gitlab.lan"],
|
||||
]);
|
||||
});
|
||||
|
||||
it("still blocks a redirect to a private host that is not listed", async () => {
|
||||
process.env.TERMIX_PLUGIN_REGISTRY_PRIVATE_HOSTS = "gitlab.lan";
|
||||
const actual = await vi.importActual<
|
||||
typeof import("../../utils/safe-outbound-fetch.js")
|
||||
>("../../utils/safe-outbound-fetch.js");
|
||||
fetchMock
|
||||
.mockResolvedValueOnce(
|
||||
response("", 302, { location: "https://127.0.0.1/index.json" }),
|
||||
)
|
||||
.mockImplementationOnce(actual.safeOutboundFetch);
|
||||
await expect(fetchIndexAt("https://gitlab.lan/index.json")).rejects.toThrow(
|
||||
"Private destinations are not allowed",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
/** A real .tmxplug holding only a manifest, enough for the checks. */
|
||||
function pack(manifest: Record<string, unknown>): Buffer {
|
||||
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "termix-pack-"));
|
||||
|
||||
Reference in new issue
Block a user