mirror of
https://github.com/fleetdm/fleet
synced 2026-05-02 19:07:38 +00:00
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
266 lines
14 KiB
JavaScript
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;
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|