fleet/ee/vulnerability-dashboard/api/helpers/get-compliance-information.js
Eric b1945b2128
Add fleet-vulnerability-dashboard repo to ee/ folder (#17428)
Closes: https://github.com/fleetdm/confidential/issues/4057

Changes:
- Added the contents of the fleet-vulnerability-dashboard repo to
ee/vulnerability-dashboard
- Added a github workflow to deploy the vulnerability dashboard on
Heroku
- Added a github workflow to test changes to the vulnerability-dashboard
- Updated the website's custom configuration to enable
auto-approvals/review requests to files in the
ee/vulnerability-dashboard folder
2024-03-13 13:06:11 -05:00

266 lines
14 KiB
JavaScript

module.exports = {
friendlyName: 'Get compliance information',
description: '',
inputs: {
complianceType: {
required: true,
type: 'string',
isIn: [
'operatingSystem',
'firefox',
'microsoftOffice',
'flash',
'chrome',
'safari',
],
},
teamApid: {
description: 'The ID of the Team to filter by, or 0 to only include hosts with no team, or undefined to not filter by any team.',
type: 'number',
},
},
exits: {
success: {
outputFriendlyName: 'Compliance information',
outputType: {
patchProgress: 'string',
versionsInUse: [{}],
compliantVersionsInUse: [{}],
}
},
},
fn: async function ({complianceType, teamApid}) {
let complianceInformation = {
patchProgress: undefined,
versionsInUse: [],
compliantVersionsInUse: []
};
let userFriendlyPlatformNamesByCodeName = {
'darwin': 'macOS',
'windows': 'Windows',
'chrome': 'Chrome OS',
'ubuntu': 'Ubuntu',
'linux': 'Linux'
};
if(complianceType === 'operatingSystem') {
// ╔═╗┌─┐┌─┐┬─┐┌─┐┌┬┐┬┌┐┌┌─┐ ┌─┐┬ ┬┌─┐┌┬┐┌─┐┌┬┐┌─┐
// ║ ║├─┘├┤ ├┬┘├─┤ │ │││││ ┬ └─┐└┬┘└─┐ │ ├┤ │││└─┐
// ╚═╝┴ └─┘┴└─┴ ┴ ┴ ┴┘└┘└─┘ └─┘ ┴ └─┘ ┴ └─┘┴ ┴└─┘
let allOperatingSystems = await OperatingSystem.find();
let idsOfCompliantOperatingSystems = _.pluck(_.where(allOperatingSystems, {isCompliant: true}), 'id');
let operatingSystemsInUse = [];
let compliantOperatingSystemsInUse = [];
for(let os of allOperatingSystems){
let osInfo = {
name: os.fullName,
sortByName: os.fullName.toLowerCase(),
hostCount: os.lastReportedHostCount,
id: os.id,
isCompliant: os.isCompliant,
};
if(os.isCompliant){
if(teamApid !== undefined){
let numberOfHostsOnThisTeamWithThisOs = await Host.count({teamApid, operatingSystem: os.id});
compliantOperatingSystemsInUse.push({
name: os.fullName,
hostCount: numberOfHostsOnThisTeamWithThisOs,
});
} else {
compliantOperatingSystemsInUse.push({
name: os.fullName,
hostCount: os.lastReportedHostCount,
});
}
}
operatingSystemsInUse.push(osInfo);
}
complianceInformation.versionsInUse = _.sortByOrder(complianceInformation.versionsInUse, 'sortByName');
let numberOfHostsToReport = await Host.count({teamApid: teamApid});
let numberOfHostsOnThisTeamWithACompliantOs = await Host.count({operatingSystem: {in: idsOfCompliantOperatingSystems}, teamApid: teamApid});
if(idsOfCompliantOperatingSystems.length !== 0){
complianceInformation.patchProgress = Math.floor(numberOfHostsOnThisTeamWithACompliantOs / numberOfHostsToReport * 100);
} else {
complianceInformation.patchProgress = undefined;
}
complianceInformation.versionsInUse = _.sortByOrder(operatingSystemsInUse, 'hostCount', 'asc');
complianceInformation.compliantVersionsInUse = compliantOperatingSystemsInUse;
} else if(complianceType === 'microsoftOffice') {
// ┌┬┐┬┌─┐┬─┐┌─┐┌─┐┌─┐┌─┐┌┬┐ ┌─┐┌─┐┌─┐┬┌─┐┌─┐
// │││││ ├┬┘│ │└─┐│ │├┤ │ │ │├┤ ├┤ ││ ├┤
// ┴ ┴┴└─┘┴└─└─┘└─┘└─┘└ ┴ └─┘└ └ ┴└─┘└─┘
let hostsOnThisTeam = [];
let hostIdsOnThisTeam = [];
let numberOfInstallsForThisTeam = undefined;
if(teamApid !== undefined) {
hostsOnThisTeam = await Host.find({teamApid: teamApid});
hostIdsOnThisTeam = _.pluck(hostsOnThisTeam, 'id');
numberOfInstallsForThisTeam = await CriticalInstall.count({softwareType: complianceType, host: {in: hostIdsOnThisTeam}});
}
// Because microsoft office is a suite of software, we'll calculate patch progress by number of hosts that have a compliant version installed, instead of the number of individual installs.
let allMicrosoftOfficeInstalls = await CriticalInstall.find({softwareType: 'microsoftOffice'});
let uniqueMicrosoftInstallsByHost = _.uniq(allMicrosoftOfficeInstalls, 'host');
let compliantMicrosoftOfficeInstalls = await CriticalInstall.find({softwareType: 'microsoftOffice', isCompliant: true});
let uniqueCompliantMicrosoftOfficeInstalls = _.uniq(compliantMicrosoftOfficeInstalls, 'host');
let microsoftOfficeVersionsInUse = [];
let compliantMicrosoftOfficeVersionsInUse = [];
let officeVersionsByPlatform = [];
let microsoftOfficeVersionsGroupedByPlatform = _.groupBy(allMicrosoftOfficeInstalls, 'platform');
for(let platform in microsoftOfficeVersionsGroupedByPlatform){
let uniqueMicrosoftOfficeVersionsForThisPlatform = _.uniq(microsoftOfficeVersionsGroupedByPlatform[platform], 'versionName');
officeVersionsByPlatform = officeVersionsByPlatform.concat(uniqueMicrosoftOfficeVersionsForThisPlatform);
}
for(let microsoftOfficeVersion of officeVersionsByPlatform) {
let userFriendlyPlatformNameForThisVersion = userFriendlyPlatformNamesByCodeName[microsoftOfficeVersion.platform];
if(userFriendlyPlatformNameForThisVersion === undefined){
userFriendlyPlatformNameForThisVersion = microsoftOfficeVersion.platform;
}
let hostCountForThisVersion = _.uniq(_.where(allMicrosoftOfficeInstalls, {versionName: microsoftOfficeVersion.versionName}), 'host').length;
let microsoftOfficeVersionInfo = {
name: `Microsoft office for ${userFriendlyPlatformNameForThisVersion} `+ microsoftOfficeVersion.versionName,
id: microsoftOfficeVersion.fleetApid,
hostCount: hostCountForThisVersion,
isCompliant: microsoftOfficeVersion.isCompliant
};
if(microsoftOfficeVersion.isCompliant){
if(teamApid !== undefined){
let allInstallsForThisVersions = _.where(compliantMicrosoftOfficeInstalls, {fleetApid: microsoftOfficeVersion.fleetApid});
let hostsWithThisVersionInstalled = _.filter(allInstallsForThisVersions, (version)=>{
return _.contains(hostIdsOnThisTeam, version.host);
});
let numberOfHostsWithThisVersionInstalled = hostsWithThisVersionInstalled.length;
compliantMicrosoftOfficeVersionsInUse.push({
name: `Microsoft Office for ${userFriendlyPlatformNameForThisVersion} `+ microsoftOfficeVersion.versionName,
hostCount: numberOfHostsWithThisVersionInstalled,
});
} else {
compliantMicrosoftOfficeVersionsInUse.push({
name: `Microsoft office for ${userFriendlyPlatformNameForThisVersion} `+ microsoftOfficeVersion.versionName,
hostCount: hostCountForThisVersion,
});
}
}
microsoftOfficeVersionsInUse.push(microsoftOfficeVersionInfo);
}
if(uniqueCompliantMicrosoftOfficeInstalls.length !== 0) {
if(teamApid !== undefined){
if(numberOfInstallsForThisTeam === 0){
complianceInformation.patchProgress = 'N/A';
} else {
let compliantMicrosoftOfficeInstallsOnThisTeam = await CriticalInstall.find({softwareType: 'microsoftOffice', isCompliant: true, host: {in: hostIdsOnThisTeam}});
let numberOfUniqueHostsOnThisTeamWithCompliantMicrosoftOfficeInstalled = _.uniq(compliantMicrosoftOfficeInstallsOnThisTeam, 'host');
let uniqueHostsOnThisTeamWithMicrosoftOfficeInstalled = _.filter(uniqueMicrosoftInstallsByHost, (install)=>{
return _.contains(hostIdsOnThisTeam, install.host);
});
if(compliantMicrosoftOfficeInstallsOnThisTeam !== 0) {
complianceInformation.patchProgress = Math.floor(numberOfUniqueHostsOnThisTeamWithCompliantMicrosoftOfficeInstalled.length / uniqueHostsOnThisTeamWithMicrosoftOfficeInstalled.length * 100);
} else {
complianceInformation.patchProgress = 0;
}
}
} else {
complianceInformation.patchProgress = Math.floor(uniqueCompliantMicrosoftOfficeInstalls.length / uniqueMicrosoftInstallsByHost.length * 100);
}
}
microsoftOfficeVersionsInUse = _.uniq(microsoftOfficeVersionsInUse);
complianceInformation.versionsInUse = _.sortByOrder(microsoftOfficeVersionsInUse, 'hostCount', 'asc');
complianceInformation.compliantVersionsInUse = compliantMicrosoftOfficeVersionsInUse;
} else {
// ┌─┐┌┬┐┬ ┬┌─┐┬─┐ ┌─┐┬─┐┬┌┬┐┬┌─┐┌─┐┬ ┌─┐┌─┐┌─┐┌┬┐┬ ┬┌─┐┬─┐┌─┐
// │ │ │ ├─┤├┤ ├┬┘ │ ├┬┘│ │ ││ ├─┤│ └─┐│ │├┤ │ │││├─┤├┬┘├┤
// └─┘ ┴ ┴ ┴└─┘┴└─ └─┘┴└─┴ ┴ ┴└─┘┴ ┴┴─┘ └─┘└─┘└ ┴ └┴┘┴ ┴┴└─└─┘
let hostsOnThisTeam = [];
let hostIdsOnThisTeam = [];
let numberOfInstallsForThisTeam = undefined;
if(teamApid !== undefined) {
hostsOnThisTeam = await Host.find({teamApid: teamApid});
hostIdsOnThisTeam = _.pluck(hostsOnThisTeam, 'id');
numberOfInstallsForThisTeam = await CriticalInstall.count({softwareType: complianceType, host: {in: hostIdsOnThisTeam}});
}
let allInstallsOfThisType = await CriticalInstall.find({softwareType: complianceType});
let compliantInstallsOfThisType = await CriticalInstall.find({softwareType: complianceType, isCompliant: true});
let versionsInUse = [];
let compliantVersionsInUse = [];
// Get the unique software items.
let uniqueVersionsInUse = _.uniq(allInstallsOfThisType, 'fleetApid');
for(let version of uniqueVersionsInUse) {
let userFriendlyPlatformNameForThisVersion = userFriendlyPlatformNamesByCodeName[version.platform];
if(userFriendlyPlatformNameForThisVersion === undefined){
userFriendlyPlatformNameForThisVersion = version.platform;
}
let hostCountForThisVersion = _.where(allInstallsOfThisType, {fleetApid: version.fleetApid}).length;
// Add information about this version to the versionsInUse array. This is used to populate the <select> options on the compliant versions forms
versionsInUse.push({
name: `${_.startCase(complianceType)} for ${userFriendlyPlatformNameForThisVersion} `+ version.versionName,
id: version.fleetApid,
hostCount: hostCountForThisVersion,
isCompliant: version.isCompliant,
});
// Add compliant versions to the compliantVersionsInUse array.
if(version.isCompliant) {
// If we're filtering by a team, we'll set the host count for each version in the compliantVersionsInUse array to be the number of hosts on the specified team with that version installed.
if(teamApid !== undefined){
let allInstallsForThisVersions = _.where(compliantInstallsOfThisType, {fleetApid: version.fleetApid});
let hostsWithThisVersionInstalled = _.filter(allInstallsForThisVersions, (version)=>{
return _.contains(hostIdsOnThisTeam, version.host);
});
let numberOfHostsWithThisVersionInstalled = hostsWithThisVersionInstalled.length;
compliantVersionsInUse.push({
name: `${_.startCase(complianceType)} for ${userFriendlyPlatformNameForThisVersion} `+ version.versionName,
hostCount: numberOfHostsWithThisVersionInstalled,
});
} else {
// Otherwise, we'll use the host count we used earlier
compliantVersionsInUse.push({
name: `${_.startCase(complianceType)} for ${userFriendlyPlatformNameForThisVersion} `+ version.versionName,
hostCount: hostCountForThisVersion,
});
}
}
}
// If a compliant version has been set for this type of software, we'll return patch progress for this complianceType.
if(compliantInstallsOfThisType.length !== 0) {
if(teamApid !== undefined){
// If there are no installs for this complianceType on this team, we will set the patch progress for this complianceType to be 'N/A'.
// In frontend land, the page will show an empty state for this table
if(numberOfInstallsForThisTeam === 0){
complianceInformation.patchProgress = 'N/A';
} else {
// If there are installs for this team, we'll use the array of host IDs to get the number of compliant installs.
let numberOfCompliantInstallsOnThisTeam = await CriticalInstall.count({softwareType: complianceType, isCompliant: true, host: {in: hostIdsOnThisTeam}});
complianceInformation.patchProgress = Math.floor(numberOfCompliantInstallsOnThisTeam / numberOfInstallsForThisTeam * 100);
}
} else {
complianceInformation.patchProgress = Math.floor(compliantInstallsOfThisType.length / allInstallsOfThisType.length * 100);
}
}
complianceInformation.versionsInUse = _.sortByOrder(versionsInUse, 'hostCount', 'asc');
complianceInformation.compliantVersionsInUse = compliantVersionsInUse;
}
// Send back the result through the success exit.
return complianceInformation;
}
};