Files
HiveGrid-Wireframes/03 Quellen und Referenzen/hivegrid-cloud/apps/web/app/utils/integrations/hrFieldCrypto.server.test.ts
T
2026-07-08 16:15:37 +02:00

42 lines
2.1 KiB
TypeScript

// @vitest-environment node
import { describe, expect, it } from "vitest";
import { deferredHrFieldCrypto, getHrFieldCrypto, HrCryptoNotProvisionedError, type HrFieldCrypto } from "./hrFieldCrypto.server";
// AK-P17a — the AD-8 per-tenant envelope (R-P5 `getTenantFieldCrypto`) is wired:
// `getHrFieldCrypto()` returns a real provider. The deferred binding is retained
// as a fail-closed scaffold (refuse to touch a sensitive value with a Klartext
// M002 message rather than silently store plaintext).
describe("hrFieldCrypto seam (bound to the R-P5 per-tenant envelope)", () => {
it("the deferred fail-closed scaffold rejects encrypt with a Klartext error", async () => {
await expect(deferredHrFieldCrypto.encrypt("tenant_1", "secret")).rejects.toBeInstanceOf(HrCryptoNotProvisionedError);
});
it("the deferred fail-closed scaffold rejects decrypt with a Klartext error", async () => {
await expect(deferredHrFieldCrypto.decrypt("tenant_1", "cipher")).rejects.toBeInstanceOf(HrCryptoNotProvisionedError);
});
it("the error carries an i18n message key, not a bare string", async () => {
const error = await deferredHrFieldCrypto.encrypt("tenant_1", "x").catch((caught) => caught);
expect(error).toBeInstanceOf(HrCryptoNotProvisionedError);
expect((error as HrCryptoNotProvisionedError).messageKey).toBe("hr.error.cryptoNotProvisioned");
});
it("getHrFieldCrypto returns a real provider, not the deferred scaffold", () => {
const crypto = getHrFieldCrypto();
expect(crypto).not.toBe(deferredHrFieldCrypto);
expect(typeof crypto.encrypt).toBe("function");
expect(typeof crypto.decrypt).toBe("function");
});
it("a working provider can be injected (proves the seam is swap-ready)", async () => {
const reversible: HrFieldCrypto = {
encrypt: (_tenantId, plaintext) => Promise.resolve(`enc:${plaintext}`),
decrypt: (_tenantId, ciphertext) => Promise.resolve(ciphertext.replace(/^enc:/, "")),
};
const cipher = await reversible.encrypt("tenant_1", "hunter2");
expect(cipher).toBe("enc:hunter2");
expect(await reversible.decrypt("tenant_1", cipher)).toBe("hunter2");
});
});