diff --git a/app/server/utils/restic/helpers/__tests__/build-env.test.ts b/app/server/utils/restic/helpers/__tests__/build-env.test.ts index 772d63a1..d9c9724a 100644 --- a/app/server/utils/restic/helpers/__tests__/build-env.test.ts +++ b/app/server/utils/restic/helpers/__tests__/build-env.test.ts @@ -36,6 +36,22 @@ const trackTempFile = (filePath: string | undefined) => { } }; +const buildEnvForTest = async ( + config: Parameters[0], + organizationId: string, +): Promise> => { + const env = await buildEnv(config, organizationId); + + // Automatically track all temp file paths created by buildEnv + trackTempFile(env.RESTIC_PASSWORD_FILE); + trackTempFile(env.GOOGLE_APPLICATION_CREDENTIALS); + trackTempFile(env._SFTP_KEY_PATH); + trackTempFile(env._SFTP_KNOWN_HOSTS_PATH); + trackTempFile(env.RESTIC_CACERT); + + return env; +}; + afterEach(async () => { await Promise.all( [...tempFiles].map(async (filePath) => { @@ -48,13 +64,13 @@ afterEach(async () => { describe("buildEnv", () => { describe("base environment", () => { test("always sets RESTIC_CACHE_DIR", async () => { - const env = await buildEnv(withCustomPassword({ backend: "local" as const, path: "/tmp/repo" }), "org-1"); + const env = await buildEnvForTest(withCustomPassword({ backend: "local" as const, path: "/tmp/repo" }), "org-1"); expect(env.RESTIC_CACHE_DIR).toBe(RESTIC_CACHE_DIR); }); test("always sets PATH", async () => { - const env = await buildEnv(withCustomPassword({ backend: "local" as const, path: "/tmp/repo" }), "org-1"); + const env = await buildEnvForTest(withCustomPassword({ backend: "local" as const, path: "/tmp/repo" }), "org-1"); expect(env.PATH).toBeTruthy(); }); @@ -62,7 +78,7 @@ describe("buildEnv", () => { describe("password resolution", () => { test("writes a password file when using customPassword on an existing repository", async () => { - const env = await buildEnv( + const env = await buildEnvForTest( { backend: "local" as const, path: "/tmp/repo", isExistingRepository: true, customPassword: "my-secret" }, "org-1", ); @@ -73,7 +89,6 @@ describe("buildEnv", () => { throw new Error("Expected password file path to be defined"); } - trackTempFile(passwordFilePath); const fileContent = await fs.readFile(passwordFilePath, "utf-8"); expect(fileContent).toBe("my-secret"); }); @@ -81,7 +96,7 @@ describe("buildEnv", () => { test("writes a password file from the organization's resticPassword when no customPassword is given", async () => { const orgId = await createTestOrg(); - const env = await buildEnv({ backend: "local" as const, path: "/tmp/repo" }, orgId); + const env = await buildEnvForTest({ backend: "local" as const, path: "/tmp/repo" }, orgId); const passwordFilePath = env.RESTIC_PASSWORD_FILE; expect(passwordFilePath).toBeDefined(); @@ -89,7 +104,6 @@ describe("buildEnv", () => { throw new Error("Expected password file path to be defined"); } - trackTempFile(passwordFilePath); const fileContent = await fs.readFile(passwordFilePath, "utf-8"); expect(fileContent).toBe("org-restic-password"); }); @@ -119,20 +133,20 @@ describe("buildEnv", () => { }); test("sets AWS credentials", async () => { - const env = await buildEnv(base, "org-1"); + const env = await buildEnvForTest(base, "org-1"); expect(env.AWS_ACCESS_KEY_ID).toBe("my-access-key"); expect(env.AWS_SECRET_ACCESS_KEY).toBe("my-secret-key"); }); test("sets AWS_S3_BUCKET_LOOKUP=dns for Huawei Cloud endpoints", async () => { - const env = await buildEnv({ ...base, endpoint: "https://obs.ap-southeast-1.myhuaweicloud.com" }, "org-1"); + const env = await buildEnvForTest({ ...base, endpoint: "https://obs.ap-southeast-1.myhuaweicloud.com" }, "org-1"); expect(env.AWS_S3_BUCKET_LOOKUP).toBe("dns"); }); test("does not set AWS_S3_BUCKET_LOOKUP for standard S3 endpoints", async () => { - const env = await buildEnv(base, "org-1"); + const env = await buildEnvForTest(base, "org-1"); expect(env.AWS_S3_BUCKET_LOOKUP).toBeUndefined(); }); @@ -140,7 +154,7 @@ describe("buildEnv", () => { describe("r2 backend", () => { test("sets AWS credentials with auto region and forced path style", async () => { - const env = await buildEnv( + const env = await buildEnvForTest( withCustomPassword({ backend: "r2" as const, endpoint: "https://myaccount.r2.cloudflarestorage.com", @@ -160,7 +174,7 @@ describe("buildEnv", () => { describe("gcs backend", () => { test("sets project ID and writes credentials file", async () => { - const env = await buildEnv( + const env = await buildEnvForTest( withCustomPassword({ backend: "gcs" as const, bucket: "my-gcs-bucket", @@ -178,7 +192,6 @@ describe("buildEnv", () => { throw new Error("Expected credentials path to be defined"); } - trackTempFile(credentialsPath); const fileContent = await fs.readFile(credentialsPath, "utf-8"); expect(fileContent).toBe('{"type":"service_account"}'); }); @@ -193,20 +206,20 @@ describe("buildEnv", () => { }); test("sets account name and key", async () => { - const env = await buildEnv(base, "org-1"); + const env = await buildEnvForTest(base, "org-1"); expect(env.AZURE_ACCOUNT_NAME).toBe("mystorageaccount"); expect(env.AZURE_ACCOUNT_KEY).toBe("my-account-key"); }); test("includes endpoint suffix when provided", async () => { - const env = await buildEnv({ ...base, endpointSuffix: "core.chinacloudapi.cn" }, "org-1"); + const env = await buildEnvForTest({ ...base, endpointSuffix: "core.chinacloudapi.cn" }, "org-1"); expect(env.AZURE_ENDPOINT_SUFFIX).toBe("core.chinacloudapi.cn"); }); test("omits endpoint suffix when not provided", async () => { - const env = await buildEnv(base, "org-1"); + const env = await buildEnvForTest(base, "org-1"); expect(env.AZURE_ENDPOINT_SUFFIX).toBeUndefined(); }); @@ -214,7 +227,7 @@ describe("buildEnv", () => { describe("rest backend", () => { test("sets username and password when both are provided", async () => { - const env = await buildEnv( + const env = await buildEnvForTest( withCustomPassword({ backend: "rest" as const, url: "https://rest-server.example.com", @@ -229,7 +242,7 @@ describe("buildEnv", () => { }); test("omits REST credentials when neither username nor password is provided", async () => { - const env = await buildEnv( + const env = await buildEnvForTest( withCustomPassword({ backend: "rest" as const, url: "https://rest-server.example.com" }), "org-1", ); @@ -269,21 +282,21 @@ describe("buildEnv", () => { }); test("uses StrictHostKeyChecking=no when skipHostKeyCheck is true", async () => { - const env = await buildEnv({ ...baseSftpConfig, skipHostKeyCheck: true }, "org-1"); + const env = await buildEnvForTest({ ...baseSftpConfig, skipHostKeyCheck: true }, "org-1"); expect(env._SFTP_SSH_ARGS).toContain("StrictHostKeyChecking=no"); expect(env._SFTP_SSH_ARGS).toContain("UserKnownHostsFile=/dev/null"); }); test("uses StrictHostKeyChecking=no when knownHosts is absent", async () => { - const env = await buildEnv({ ...baseSftpConfig, skipHostKeyCheck: false, knownHosts: undefined }, "org-1"); + const env = await buildEnvForTest({ ...baseSftpConfig, skipHostKeyCheck: false, knownHosts: undefined }, "org-1"); expect(env._SFTP_SSH_ARGS).toContain("StrictHostKeyChecking=no"); expect(env._SFTP_SSH_ARGS).toContain("UserKnownHostsFile=/dev/null"); }); test("uses StrictHostKeyChecking=yes and a known hosts file when knownHosts is provided", async () => { - const env = await buildEnv( + const env = await buildEnvForTest( { ...baseSftpConfig, skipHostKeyCheck: false, @@ -298,19 +311,19 @@ describe("buildEnv", () => { }); test("adds -p flag for non-default ports", async () => { - const env = await buildEnv({ ...baseSftpConfig, port: 2222 }, "org-1"); + const env = await buildEnvForTest({ ...baseSftpConfig, port: 2222 }, "org-1"); expect(env._SFTP_SSH_ARGS).toContain("-p 2222"); }); test("omits -p flag for the default port 22", async () => { - const env = await buildEnv({ ...baseSftpConfig, port: 22 }, "org-1"); + const env = await buildEnvForTest({ ...baseSftpConfig, port: 22 }, "org-1"); expect(env._SFTP_SSH_ARGS).not.toContain("-p 22"); }); test("sets the key path in both _SFTP_KEY_PATH and SSH args -i flag", async () => { - const env = await buildEnv(baseSftpConfig, "org-1"); + const env = await buildEnvForTest(baseSftpConfig, "org-1"); expect(env._SFTP_KEY_PATH).toMatch(/^\/tmp\/zerobyte-ssh-/); expect(env._SFTP_SSH_ARGS).toContain(`-i ${env._SFTP_KEY_PATH}`); @@ -319,7 +332,7 @@ describe("buildEnv", () => { describe("cacert", () => { test("sets RESTIC_CACERT pointing to a temp file when cacert is provided", async () => { - const env = await buildEnv( + const env = await buildEnvForTest( withCustomPassword({ backend: "local" as const, path: "/tmp/repo", @@ -334,13 +347,12 @@ describe("buildEnv", () => { throw new Error("Expected certificate path to be defined"); } - trackTempFile(certPath); const fileContent = await fs.readFile(certPath, "utf-8"); expect(fileContent).toBe("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"); }); test("does not set RESTIC_CACERT when cacert is absent", async () => { - const env = await buildEnv(withCustomPassword({ backend: "local" as const, path: "/tmp/repo" }), "org-1"); + const env = await buildEnvForTest(withCustomPassword({ backend: "local" as const, path: "/tmp/repo" }), "org-1"); expect(env.RESTIC_CACERT).toBeUndefined(); }); @@ -348,7 +360,7 @@ describe("buildEnv", () => { describe("insecure TLS", () => { test("sets _INSECURE_TLS=true when insecureTls is true", async () => { - const env = await buildEnv( + const env = await buildEnvForTest( withCustomPassword({ backend: "local" as const, path: "/tmp/repo", insecureTls: true }), "org-1", ); @@ -357,7 +369,7 @@ describe("buildEnv", () => { }); test("does not set _INSECURE_TLS when insecureTls is absent", async () => { - const env = await buildEnv(withCustomPassword({ backend: "local" as const, path: "/tmp/repo" }), "org-1"); + const env = await buildEnvForTest(withCustomPassword({ backend: "local" as const, path: "/tmp/repo" }), "org-1"); expect(env._INSECURE_TLS).toBeUndefined(); });