/**
* @vitest-environment node
*/
import {
ReportType,
ReportStatus,
ReportTrend,
SeverityDistribution,
SecurityIssueStat,
ComplianceReport,
VulnerabilitySeverity,
PackageVersionType,
VulnerabilityReachability,
VulnerabilityFixability,
Package,
PackageVersion,
Vulnerability,
VulnerabilityOccurrence,
DependencyVulnerabilitiesParams,
VulnerabilitiesResponse,
} from '../../models/security';
describe('Security Models', () => {
describe('Enum Types', () => {
describe('ReportType', () => {
it('should define the correct report types', () => {
// Compliance-specific report types
expect(ReportType.OWASP_TOP_10).toBe('OWASP_TOP_10');
expect(ReportType.SANS_TOP_25).toBe('SANS_TOP_25');
expect(ReportType.MISRA_C).toBe('MISRA_C');
// General report types
expect(ReportType.CODE_COVERAGE).toBe('CODE_COVERAGE');
expect(ReportType.CODE_HEALTH_TREND).toBe('CODE_HEALTH_TREND');
expect(ReportType.ISSUE_DISTRIBUTION).toBe('ISSUE_DISTRIBUTION');
expect(ReportType.ISSUES_PREVENTED).toBe('ISSUES_PREVENTED');
expect(ReportType.ISSUES_AUTOFIXED).toBe('ISSUES_AUTOFIXED');
});
it('should have the correct number of values', () => {
expect(Object.keys(ReportType).length).toBe(8);
});
});
describe('ReportStatus', () => {
it('should define the correct report statuses', () => {
expect(ReportStatus.PASSING).toBe('PASSING');
expect(ReportStatus.FAILING).toBe('FAILING');
expect(ReportStatus.NOOP).toBe('NOOP');
});
it('should have the correct number of values', () => {
expect(Object.keys(ReportStatus).length).toBe(3);
});
});
});
describe('Type Definitions', () => {
describe('VulnerabilitySeverity', () => {
it('should allow valid severity levels', () => {
const severities: VulnerabilitySeverity[] = ['NONE', 'LOW', 'MEDIUM', 'HIGH', 'CRITICAL'];
severities.forEach((severity) => {
expect(typeof severity).toBe('string');
});
});
});
describe('PackageVersionType', () => {
it('should allow valid version types', () => {
const versionTypes: PackageVersionType[] = ['SEMVER', 'ECOSYSTEM', 'GIT'];
versionTypes.forEach((type) => {
expect(typeof type).toBe('string');
});
});
});
describe('VulnerabilityReachability', () => {
it('should allow valid reachability types', () => {
const reachabilityTypes: VulnerabilityReachability[] = [
'REACHABLE',
'UNREACHABLE',
'UNKNOWN',
];
reachabilityTypes.forEach((type) => {
expect(typeof type).toBe('string');
});
});
});
describe('VulnerabilityFixability', () => {
it('should allow valid fixability types', () => {
const fixabilityTypes: VulnerabilityFixability[] = [
'ERROR',
'UNFIXABLE',
'GENERATING_FIX',
'POSSIBLY_FIXABLE',
'MANUALLY_FIXABLE',
'AUTO_FIXABLE',
];
fixabilityTypes.forEach((type) => {
expect(typeof type).toBe('string');
});
});
});
});
describe('Interface Type Checking', () => {
describe('ReportTrend', () => {
it('should validate a report trend with all fields', () => {
const trend: ReportTrend = {
label: 'Last 30 days',
value: 85.5,
changePercentage: 3.2,
};
expect(trend.label).toBe('Last 30 days');
expect(trend.value).toBe(85.5);
expect(trend.changePercentage).toBe(3.2);
});
it('should allow optional fields to be undefined', () => {
const trend: ReportTrend = {};
expect(trend.label).toBeUndefined();
expect(trend.value).toBeUndefined();
expect(trend.changePercentage).toBeUndefined();
});
});
describe('SeverityDistribution', () => {
it('should validate a severity distribution', () => {
const distribution: SeverityDistribution = {
critical: 5,
major: 15,
minor: 30,
total: 50,
};
expect(distribution.critical).toBe(5);
expect(distribution.major).toBe(15);
expect(distribution.minor).toBe(30);
expect(distribution.total).toBe(50);
});
});
describe('SecurityIssueStat', () => {
it('should validate a security issue stat', () => {
const stat: SecurityIssueStat = {
key: 'A1:2017',
title: 'Injection',
occurrence: {
critical: 2,
major: 5,
minor: 10,
total: 17,
},
};
expect(stat.key).toBe('A1:2017');
expect(stat.title).toBe('Injection');
expect(stat.occurrence.total).toBe(17);
});
});
describe('ComplianceReport', () => {
it('should validate a complete compliance report', () => {
const report: ComplianceReport = {
key: ReportType.OWASP_TOP_10,
title: 'OWASP Top 10',
currentValue: 85.5,
status: ReportStatus.PASSING,
securityIssueStats: [
{
key: 'A1:2017',
title: 'Injection',
occurrence: {
critical: 0,
major: 0,
minor: 0,
total: 0,
},
},
{
key: 'A2:2017',
title: 'Broken Authentication',
occurrence: {
critical: 1,
major: 2,
minor: 0,
total: 3,
},
},
],
trends: [
{
label: 'Last 30 days',
value: 82.3,
changePercentage: 3.2,
},
],
};
expect(report.key).toBe(ReportType.OWASP_TOP_10);
expect(report.title).toBe('OWASP Top 10');
expect(report.currentValue).toBe(85.5);
expect(report.status).toBe(ReportStatus.PASSING);
expect(report.securityIssueStats.length).toBe(2);
expect(report.securityIssueStats[1].key).toBe('A2:2017');
expect(report.trends?.[0].changePercentage).toBe(3.2);
});
it('should allow optional fields to be undefined', () => {
const report: ComplianceReport = {
key: ReportType.SANS_TOP_25,
title: 'SANS Top 25',
securityIssueStats: [],
};
expect(report.currentValue).toBeUndefined();
expect(report.status).toBeUndefined();
expect(report.trends).toBeUndefined();
});
});
describe('Package', () => {
it('should validate a complete package', () => {
const pkg: Package = {
id: 'pkg_123',
ecosystem: 'NPM',
name: 'lodash',
purl: 'pkg:npm/lodash@4.17.21',
};
expect(pkg.id).toBe('pkg_123');
expect(pkg.ecosystem).toBe('NPM');
expect(pkg.name).toBe('lodash');
expect(pkg.purl).toBe('pkg:npm/lodash@4.17.21');
});
it('should allow optional fields to be undefined', () => {
const pkg: Package = {
id: 'pkg_123',
ecosystem: 'NPM',
name: 'lodash',
};
expect(pkg.purl).toBeUndefined();
});
});
describe('PackageVersion', () => {
it('should validate a complete package version', () => {
const version: PackageVersion = {
id: 'ver_123',
version: '4.17.21',
versionType: 'SEMVER',
};
expect(version.id).toBe('ver_123');
expect(version.version).toBe('4.17.21');
expect(version.versionType).toBe('SEMVER');
});
it('should allow optional fields to be undefined', () => {
const version: PackageVersion = {
id: 'ver_123',
version: '4.17.21',
};
expect(version.versionType).toBeUndefined();
});
});
describe('Vulnerability', () => {
it('should validate a complete vulnerability', () => {
const vulnerability: Vulnerability = {
id: 'vuln_123',
identifier: 'CVE-2022-1234',
aliases: ['GHSA-abcd-efgh-ijkl'],
summary: 'Prototype pollution vulnerability',
details: 'A detailed description of the vulnerability...',
publishedAt: '2022-05-15T10:30:00Z',
updatedAt: '2022-06-01T14:45:00Z',
withdrawnAt: undefined,
severity: 'HIGH',
cvssV2Vector: 'AV:N/AC:L/Au:N/C:P/I:P/A:P',
cvssV2BaseScore: 7.5,
cvssV2Severity: 'HIGH',
cvssV3Vector: 'CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H',
cvssV3BaseScore: 9.8,
cvssV3Severity: 'CRITICAL',
cvssV4Vector: 'CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H',
cvssV4BaseScore: 10.0,
cvssV4Severity: 'CRITICAL',
epssScore: 0.85,
epssPercentile: 0.95,
introducedVersions: ['4.0.0'],
fixedVersions: ['4.17.21'],
referenceUrls: ['https://nvd.nist.gov/vuln/detail/CVE-2022-1234'],
};
expect(vulnerability.id).toBe('vuln_123');
expect(vulnerability.identifier).toBe('CVE-2022-1234');
expect(vulnerability.aliases).toContain('GHSA-abcd-efgh-ijkl');
expect(vulnerability.severity).toBe('HIGH');
expect(vulnerability.cvssV3BaseScore).toBe(9.8);
expect(vulnerability.cvssV3Severity).toBe('CRITICAL');
expect(vulnerability.epssScore).toBe(0.85);
expect(vulnerability.introducedVersions).toContain('4.0.0');
expect(vulnerability.fixedVersions).toContain('4.17.21');
});
it('should allow optional fields to be undefined', () => {
const vulnerability: Vulnerability = {
id: 'vuln_123',
identifier: 'CVE-2022-1234',
aliases: [],
publishedAt: '2022-05-15T10:30:00Z',
updatedAt: '2022-06-01T14:45:00Z',
severity: 'HIGH',
introducedVersions: [],
fixedVersions: [],
referenceUrls: [],
};
expect(vulnerability.summary).toBeUndefined();
expect(vulnerability.details).toBeUndefined();
expect(vulnerability.withdrawnAt).toBeUndefined();
expect(vulnerability.cvssV2Vector).toBeUndefined();
expect(vulnerability.cvssV2BaseScore).toBeUndefined();
expect(vulnerability.cvssV2Severity).toBeUndefined();
expect(vulnerability.cvssV3Vector).toBeUndefined();
expect(vulnerability.cvssV3BaseScore).toBeUndefined();
expect(vulnerability.cvssV3Severity).toBeUndefined();
expect(vulnerability.cvssV4Vector).toBeUndefined();
expect(vulnerability.cvssV4BaseScore).toBeUndefined();
expect(vulnerability.cvssV4Severity).toBeUndefined();
expect(vulnerability.epssScore).toBeUndefined();
expect(vulnerability.epssPercentile).toBeUndefined();
});
});
describe('VulnerabilityOccurrence', () => {
it('should validate a complete vulnerability occurrence', () => {
const occurrence: VulnerabilityOccurrence = {
id: 'occ_123',
package: {
id: 'pkg_123',
ecosystem: 'NPM',
name: 'lodash',
purl: 'pkg:npm/lodash',
},
packageVersion: {
id: 'ver_123',
version: '4.17.20',
versionType: 'SEMVER',
},
vulnerability: {
id: 'vuln_123',
identifier: 'CVE-2022-1234',
aliases: ['GHSA-abcd-efgh-ijkl'],
publishedAt: '2022-05-15T10:30:00Z',
updatedAt: '2022-06-01T14:45:00Z',
severity: 'HIGH',
introducedVersions: ['4.0.0'],
fixedVersions: ['4.17.21'],
referenceUrls: [],
},
reachability: 'REACHABLE',
fixability: 'AUTO_FIXABLE',
};
expect(occurrence.id).toBe('occ_123');
expect(occurrence.package.name).toBe('lodash');
expect(occurrence.packageVersion.version).toBe('4.17.20');
expect(occurrence.vulnerability.identifier).toBe('CVE-2022-1234');
expect(occurrence.reachability).toBe('REACHABLE');
expect(occurrence.fixability).toBe('AUTO_FIXABLE');
});
});
describe('DependencyVulnerabilitiesParams', () => {
it('should validate dependency vulnerabilities params', () => {
const params: DependencyVulnerabilitiesParams = {
projectKey: 'project_123',
first: 10,
after: 'cursor123',
};
expect(params.projectKey).toBe('project_123');
expect(params.first).toBe(10);
expect(params.after).toBe('cursor123');
});
});
describe('VulnerabilitiesResponse', () => {
it('should validate vulnerabilities response structure', () => {
const response: VulnerabilitiesResponse = {
edges: [
{
node: {
id: 'occ_123',
package: {
id: 'pkg_123',
ecosystem: 'NPM',
name: 'lodash',
purl: 'pkg:npm/lodash',
},
packageVersion: {
id: 'ver_123',
version: '4.17.20',
versionType: 'SEMVER',
},
vulnerability: {
id: 'vuln_123',
identifier: 'CVE-2022-1234',
aliases: [],
publishedAt: '2022-05-15T10:30:00Z',
updatedAt: '2022-06-01T14:45:00Z',
severity: 'HIGH',
introducedVersions: [],
fixedVersions: [],
referenceUrls: [],
},
reachability: 'REACHABLE',
fixability: 'AUTO_FIXABLE',
},
cursor: 'cursor123',
},
],
pageInfo: {
hasNextPage: true,
hasPreviousPage: false,
startCursor: 'cursor123',
endCursor: 'cursor123',
},
totalCount: 1,
};
expect(response.edges.length).toBe(1);
expect(response.edges[0].node.id).toBe('occ_123');
expect(response.edges[0].node.package.name).toBe('lodash');
expect(response.pageInfo.hasNextPage).toBe(true);
expect(response.totalCount).toBe(1);
});
it('should validate empty response', () => {
const response: VulnerabilitiesResponse = {
edges: [],
pageInfo: {
hasNextPage: false,
hasPreviousPage: false,
startCursor: null,
endCursor: null,
},
totalCount: 0,
};
expect(response.edges.length).toBe(0);
expect(response.totalCount).toBe(0);
});
});
});
// Test JSON serialization and deserialization
describe('JSON Serialization & Deserialization', () => {
it('should correctly serialize and deserialize vulnerability object', () => {
const original: Vulnerability = {
id: 'vuln_123',
identifier: 'CVE-2022-1234',
aliases: ['GHSA-abcd-efgh-ijkl'],
summary: 'Prototype pollution vulnerability',
details: 'A detailed description of the vulnerability...',
publishedAt: '2022-05-15T10:30:00Z',
updatedAt: '2022-06-01T14:45:00Z',
severity: 'HIGH',
cvssV3Vector: 'CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H',
cvssV3BaseScore: 9.8,
cvssV3Severity: 'CRITICAL',
introducedVersions: ['4.0.0'],
fixedVersions: ['4.17.21'],
referenceUrls: ['https://nvd.nist.gov/vuln/detail/CVE-2022-1234'],
};
const json = JSON.stringify(original);
const deserialized = JSON.parse(json) as Vulnerability;
expect(deserialized).toEqual(original);
expect(deserialized.id).toBe('vuln_123');
expect(deserialized.severity).toBe('HIGH');
expect(deserialized.cvssV3Severity).toBe('CRITICAL');
});
it('should correctly serialize and deserialize compliance report', () => {
const original: ComplianceReport = {
key: ReportType.OWASP_TOP_10,
title: 'OWASP Top 10',
currentValue: 85.5,
status: ReportStatus.PASSING,
securityIssueStats: [
{
key: 'A1:2017',
title: 'Injection',
occurrence: {
critical: 0,
major: 0,
minor: 0,
total: 0,
},
},
],
trends: [
{
label: 'Last 30 days',
value: 82.3,
changePercentage: 3.2,
},
],
};
const json = JSON.stringify(original);
const deserialized = JSON.parse(json) as ComplianceReport;
expect(deserialized).toEqual(original);
expect(deserialized.key).toBe(ReportType.OWASP_TOP_10);
expect(deserialized.status).toBe(ReportStatus.PASSING);
});
});
});