import { describe, it, expect } from "vitest"; import { OrgPolicySchema, OrgPolicyUpdateSchema, parseStoredPolicy, type OrgPolicy } from "./policy.schema.js"; import { effectiveMaxFileBytes, planMaxFileBytes } from "./org-policy.service.js"; import { PLAN_USAGE_LIMITS } from "../files/quota.js"; /** A policy with only the size cap set (the rest at defaults). */ const withCap = (mb: number): OrgPolicy => parseStoredPolicy({ maxFileSizeMB: mb }); describe("OrgPolicy schema", () => { it("defaults are the PERMISSIVE baseline (backward compat — rule 6)", () => { const p = OrgPolicySchema.parse({}); expect(p).toEqual({ require2FA: false, ssoEnforced: false, disableGuestPublicShare: false, allowExternalEmbeds: true // maxFileSizeMB / sessionLifetimeHours absent → plan cap / platform TTL }); }); it("parseStoredPolicy tolerates null / non-object / unknown keys", () => { expect(parseStoredPolicy(null)).toEqual(OrgPolicySchema.parse({})); expect(parseStoredPolicy(undefined)).toEqual(OrgPolicySchema.parse({})); expect(parseStoredPolicy("junk")).toEqual(OrgPolicySchema.parse({})); const p = parseStoredPolicy({ require2FA: true, futureField: 42 }); expect(p.require2FA).toBe(true); expect("futureField" in p).toBe(false); }); it("parseStoredPolicy parses a full stored policy", () => { const p = parseStoredPolicy({ require2FA: true, ssoEnforced: true, disableGuestPublicShare: true, maxFileSizeMB: 100, sessionLifetimeHours: 12, allowExternalEmbeds: false }); expect(p.require2FA).toBe(true); expect(p.ssoEnforced).toBe(true); expect(p.disableGuestPublicShare).toBe(true); expect(p.maxFileSizeMB).toBe(100); expect(p.sessionLifetimeHours).toBe(12); expect(p.allowExternalEmbeds).toBe(false); }); it("maxFileSizeMB bounds (1..10240)", () => { expect(OrgPolicySchema.parse({ maxFileSizeMB: 1 }).maxFileSizeMB).toBe(1); expect(OrgPolicySchema.parse({ maxFileSizeMB: 10240 }).maxFileSizeMB).toBe(10240); expect(() => OrgPolicySchema.parse({ maxFileSizeMB: 0 })).toThrow(); expect(() => OrgPolicySchema.parse({ maxFileSizeMB: 10241 })).toThrow(); expect(() => OrgPolicySchema.parse({ maxFileSizeMB: 1.5 })).toThrow(); }); it("sessionLifetimeHours bounds (1..720)", () => { expect(OrgPolicySchema.parse({ sessionLifetimeHours: 1 }).sessionLifetimeHours).toBe(1); expect(OrgPolicySchema.parse({ sessionLifetimeHours: 720 }).sessionLifetimeHours).toBe(720); expect(() => OrgPolicySchema.parse({ sessionLifetimeHours: 0 })).toThrow(); expect(() => OrgPolicySchema.parse({ sessionLifetimeHours: 721 })).toThrow(); }); it("update schema requires at least one field, allows null (clear)", () => { expect(() => OrgPolicyUpdateSchema.parse({})).toThrow(); expect(OrgPolicyUpdateSchema.parse({ require2FA: true })).toEqual({ require2FA: true }); expect(OrgPolicyUpdateSchema.parse({ maxFileSizeMB: null }).maxFileSizeMB).toBeNull(); }); }); describe("plan / effective max-file-size caps", () => { it("planMaxFileBytes honors the plan (free 50MB, paid 500MB, unknown → free)", () => { expect(planMaxFileBytes("free")).toBe(PLAN_USAGE_LIMITS.free!.maxFileSize); expect(planMaxFileBytes("paid")).toBe(PLAN_USAGE_LIMITS.paid!.maxFileSize); expect(planMaxFileBytes("nope")).toBe(PLAN_USAGE_LIMITS.free!.maxFileSize); }); it("org policy caps the plan (TIGHTEN only)", () => { // free plan (50MB) + a 10MB org cap → 10MB. expect(effectiveMaxFileBytes(withCap(10), "free")).toBe(10 * 1024 * 1024); // paid plan (500MB) + a 200MB org cap → 200MB. expect(effectiveMaxFileBytes(withCap(200), "paid")).toBe(200 * 1024 * 1024); }); it("an org cap ABOVE the plan cannot raise it (plan ceiling wins)", () => { // free plan 50MB + a 500MB org cap → still 50MB. expect(effectiveMaxFileBytes(withCap(500), "free")).toBe(PLAN_USAGE_LIMITS.free!.maxFileSize); }); it("no org cap (null / unset) → the plan cap (current behavior)", () => { expect(effectiveMaxFileBytes(null, "free")).toBe(PLAN_USAGE_LIMITS.free!.maxFileSize); expect(effectiveMaxFileBytes(parseStoredPolicy({}), "paid")).toBe( PLAN_USAGE_LIMITS.paid!.maxFileSize ); }); });