1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-03 02:03:53 +00:00

Critical: Add comprehensive test coverage for backward compatibility

Add test cases for the primary use case addressed by this PR: validating
OrganizationReportSummary objects without the newApplications field.

Tests added:
- isOrganizationReportSummary accepts objects without newApplications
- isOrganizationReportSummary accepts objects with undefined newApplications
- validateOrganizationReportSummary accepts objects without newApplications
- validateOrganizationReportSummary accepts objects with undefined newApplications
- Validation enforces empty string rejection when newApplications is present
- Validation enforces array length limits when newApplications is present
- Validation enforces string length limits when newApplications is present

This prevents regression where legacy encrypted data (which predates the
newApplications field) would fail to decrypt.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Claude
2025-10-30 05:20:10 +00:00
parent b634c1afa9
commit 2ad769a6cb

View File

@@ -247,6 +247,76 @@ describe("Risk Insights Type Guards", () => {
/Invalid OrganizationReportSummary/,
);
});
// Backward compatibility tests - legacy encrypted data predates newApplications field
it("should accept OrganizationReportSummary without newApplications field (backward compatibility)", () => {
const validLegacyData = {
totalMemberCount: 10,
totalApplicationCount: 5,
totalAtRiskMemberCount: 2,
totalAtRiskApplicationCount: 1,
totalCriticalApplicationCount: 3,
totalCriticalMemberCount: 4,
totalCriticalAtRiskMemberCount: 1,
totalCriticalAtRiskApplicationCount: 1,
// newApplications field intentionally omitted - legacy data
};
expect(() => validateOrganizationReportSummary(validLegacyData)).not.toThrow();
expect(validateOrganizationReportSummary(validLegacyData)).toEqual(validLegacyData);
});
it("should accept OrganizationReportSummary with undefined newApplications (backward compatibility)", () => {
const validData = {
totalMemberCount: 10,
totalApplicationCount: 5,
totalAtRiskMemberCount: 2,
totalAtRiskApplicationCount: 1,
totalCriticalApplicationCount: 3,
totalCriticalMemberCount: 4,
totalCriticalAtRiskMemberCount: 1,
totalCriticalAtRiskApplicationCount: 1,
newApplications: undefined,
};
expect(() => validateOrganizationReportSummary(validData)).not.toThrow();
});
it("should enforce array length limits on newApplications when present", () => {
const invalidData = {
totalMemberCount: 10,
totalApplicationCount: 5,
totalAtRiskMemberCount: 2,
totalAtRiskApplicationCount: 1,
totalCriticalApplicationCount: 3,
totalCriticalMemberCount: 4,
totalCriticalAtRiskMemberCount: 1,
totalCriticalAtRiskApplicationCount: 1,
newApplications: new Array(50001).fill("app"), // exceeds MAX_ARRAY_LENGTH
};
expect(() => validateOrganizationReportSummary(invalidData)).toThrow(
/Invalid OrganizationReportSummary.*newApplications/,
);
});
it("should enforce string length limits on newApplications when present", () => {
const invalidData = {
totalMemberCount: 10,
totalApplicationCount: 5,
totalAtRiskMemberCount: 2,
totalAtRiskApplicationCount: 1,
totalCriticalApplicationCount: 3,
totalCriticalMemberCount: 4,
totalCriticalAtRiskMemberCount: 1,
totalCriticalAtRiskApplicationCount: 1,
newApplications: ["app-1", "a".repeat(1001)], // exceeds MAX_STRING_LENGTH
};
expect(() => validateOrganizationReportSummary(invalidData)).toThrow(
/Invalid OrganizationReportSummary.*newApplications/,
);
});
});
describe("validateOrganizationReportApplicationArray", () => {
@@ -616,6 +686,82 @@ describe("Risk Insights Type Guards", () => {
};
expect(isOrganizationReportSummary(invalidData)).toBe(false);
});
// Backward compatibility tests - legacy encrypted data predates newApplications field
it("should return true for OrganizationReportSummary without newApplications field (backward compatibility)", () => {
const validLegacyData = {
totalMemberCount: 10,
totalApplicationCount: 5,
totalAtRiskMemberCount: 2,
totalAtRiskApplicationCount: 1,
totalCriticalApplicationCount: 3,
totalCriticalMemberCount: 4,
totalCriticalAtRiskMemberCount: 1,
totalCriticalAtRiskApplicationCount: 1,
// newApplications field intentionally omitted - legacy data
};
expect(isOrganizationReportSummary(validLegacyData)).toBe(true);
});
it("should return true for OrganizationReportSummary with undefined newApplications (backward compatibility)", () => {
const validData = {
totalMemberCount: 10,
totalApplicationCount: 5,
totalAtRiskMemberCount: 2,
totalAtRiskApplicationCount: 1,
totalCriticalApplicationCount: 3,
totalCriticalMemberCount: 4,
totalCriticalAtRiskMemberCount: 1,
totalCriticalAtRiskApplicationCount: 1,
newApplications: undefined,
};
expect(isOrganizationReportSummary(validData)).toBe(true);
});
it("should return false for empty string in newApplications when present", () => {
const invalidData = {
totalMemberCount: 10,
totalApplicationCount: 5,
totalAtRiskMemberCount: 2,
totalAtRiskApplicationCount: 1,
totalCriticalApplicationCount: 3,
totalCriticalMemberCount: 4,
totalCriticalAtRiskMemberCount: 1,
totalCriticalAtRiskApplicationCount: 1,
newApplications: ["app-1", "", "app-3"], // empty string should be rejected
};
expect(isOrganizationReportSummary(invalidData)).toBe(false);
});
it("should return false when newApplications exceeds array length limit", () => {
const invalidData = {
totalMemberCount: 10,
totalApplicationCount: 5,
totalAtRiskMemberCount: 2,
totalAtRiskApplicationCount: 1,
totalCriticalApplicationCount: 3,
totalCriticalMemberCount: 4,
totalCriticalAtRiskMemberCount: 1,
totalCriticalAtRiskApplicationCount: 1,
newApplications: new Array(50001).fill("app"), // exceeds MAX_ARRAY_LENGTH
};
expect(isOrganizationReportSummary(invalidData)).toBe(false);
});
it("should return false when newApplications contains strings exceeding length limit", () => {
const invalidData = {
totalMemberCount: 10,
totalApplicationCount: 5,
totalAtRiskMemberCount: 2,
totalAtRiskApplicationCount: 1,
totalCriticalApplicationCount: 3,
totalCriticalMemberCount: 4,
totalCriticalAtRiskMemberCount: 1,
totalCriticalAtRiskApplicationCount: 1,
newApplications: ["app-1", "a".repeat(1001)], // exceeds MAX_STRING_LENGTH
};
expect(isOrganizationReportSummary(invalidData)).toBe(false);
});
});
describe("isOrganizationReportApplication", () => {