Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/com/fuse/actions/assessment/AddVulnerability.java
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,13 @@ else if (tmpRec == null)
html += "<td data-sort='" + vuln.getOverall() + "'><span class='vulnName'>" + StringEscapeUtils.escapeHtml4(vuln.getName()) +"</span><br>";
html += "<span class='category'>" + (vuln.getDefaultVuln() == null ? ""
: StringEscapeUtils.escapeHtml4(vuln.getDefaultVuln().getCategory().getName())) + "</span><br>";
html += "<span class='severity'>" + vuln.getOverallStr() + "</span></td>";
html += "<span class='severity'>" + vuln.getOverallStr() + "</span>";

if(this.getSectionsEnabled()) {
html += "<br/><span class='sectionName'>" + vuln.getSectionPretty() + "</span></td>";
}else {
html += "</td>";
}
html += "<td><span class='vulnControl vulnControl-delete' id='deleteVuln"
+ vuln.getId() + "'><i class='fa fa-trash' title='Delete Vulnerability'> </i></span></td>";
html += "</tr>";
Expand Down
5 changes: 3 additions & 2 deletions src/com/fuse/actions/remediation/OpenVulns.java
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,10 @@ public String execute() {
}

if (this.closed.equals("") && !this.open.equals("")) {
// open = anything whose status does not say "Closed"
// open = not closed in production. Items closed in dev
// or staging are still open in prod, so they stay here.
newMongo += " 'vuln.closed' : {'$exists':false}, "
+ " 'vuln.status' : {'$nin': " + VulnerabilityQueries.closedStatusArray() + "}, ";
+ " 'vuln.status' : {'$ne': \"" + Vulnerability.StatusClosed + "\"}, ";
} else if (!this.closed.equals("") && this.open.equals("")) { // show only closed items
newMongo += " '$or' : [ {'vuln.closed' : {'$exists':true}}, "
+ "{'vuln.status' : {'$in': " + VulnerabilityQueries.closedStatusArray() + "}} ], ";
Expand Down
2 changes: 1 addition & 1 deletion src/com/fuse/dao/Vulnerability.java
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ public void setCvssString(String cvssString) {
}

public String getSection() {
return this.section == null || this.section == ""? "Default" : this.section.replaceAll("_", " ");
return this.section == null || this.section == ""? "Default" : this.section.replaceAll(" ", "_");
}

public void setSection(String section) {
Expand Down
11 changes: 8 additions & 3 deletions src/com/fuse/dao/query/VulnerabilityQueries.java
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,11 @@ public static void saveAll(FSActionSupport sender, Vulnerability vuln, EntityMan
HibHelper.getInstance().commit();
}

// Mongo array of the statuses that mean a vulnerability is no longer open.
// Every other status (or a missing status on legacy documents) is open.
// Mongo array of the statuses that mean a vulnerability is closed in
// some environment (prod, dev, or staging). Used to match items that are
// explicitly "closed". Note that dev/staging-closed items are still
// open in production, so the "open" filters compare against StatusClosed
// only, not this array.
public static String closedStatusArray() {
return "[\"" + Vulnerability.StatusClosed + "\", \"" + Vulnerability.StatusClosedInDev + "\", \""
+ Vulnerability.StatusClosedInStaging + "\"]";
Expand All @@ -295,8 +298,10 @@ public static List<Vulnerability> getOpenVulns(EntityManager em) {
trackedLevels += "" + level.getRiskId() + ",";
}
}
// Open = not closed in production. Items closed in dev or staging
// are still open in prod, so they stay in the past-due list.
String mongo = "{\"overall\" : {\"$in\": [" + trackedLevels + "]}, " + "\"closed\" : { \"$exists\" : false},"
+ "\"status\" : { \"$nin\" : " + closedStatusArray() + "},"
+ "\"status\" : { \"$ne\" : \"" + Vulnerability.StatusClosed + "\"},"
+ "\"opened\" : { \"$exists\" : true}" + "}";
return em.createNativeQuery(mongo, Vulnerability.class).getResultList();
}
Expand Down
140 changes: 140 additions & 0 deletions test/com/fuse/dao/query/VulnerabilityQueriesOpenVulnsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package com.fuse.dao.query;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.util.Date;
import java.util.List;
import java.util.UUID;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

import com.fuse.api.MongoTestBase;
import com.fuse.dao.HibHelper;
import com.fuse.dao.RiskLevel;
import com.fuse.dao.Vulnerability;

/**
* Verifies the "open" semantics used by the remediation past-due queue:
* only vulnerabilities closed in production (status "Closed") are excluded.
* Items closed in dev or staging are still open in production and must
* remain in the open list.
*/
public class VulnerabilityQueriesOpenVulnsTest extends MongoTestBase {

private static EntityManagerFactory emf;
private static Long riskLevelId;
private static int testRiskId;
private static String tag;
private static Long openVulnId;
private static Long devClosedVulnId;
private static Long stagingClosedVulnId;
private static Long prodClosedVulnId;

@BeforeClass
public static void setupFixtures() {
emf = HibHelper.getInstance().getEMF();
org.junit.Assume.assumeNotNull(
"EntityManagerFactory unavailable — skipping integration test",
emf);

tag = UUID.randomUUID().toString().substring(0, 8);
testRiskId = 10000 + (int) (Math.random() * 89999);

EntityManager em = emf.createEntityManager();
try {
RiskLevel rl = new RiskLevel();
rl.setRiskId(testRiskId);
rl.setRisk("open-vulns-test-" + tag);
rl.setDaysTillDue(30);
persist(em, rl);
riskLevelId = rl.getId();

openVulnId = persistVuln(em, "open-" + tag, Vulnerability.StatusOpen, null, null, null);
devClosedVulnId = persistVuln(em, "dev-" + tag, Vulnerability.StatusClosedInDev, new Date(), null, null);
stagingClosedVulnId = persistVuln(em, "staging-" + tag, Vulnerability.StatusClosedInStaging, null, new Date(), null);
prodClosedVulnId = persistVuln(em, "prod-" + tag, Vulnerability.StatusClosed, null, null, new Date());
} finally {
em.close();
}
}

private static void persist(EntityManager em, Object entity) {
HibHelper.getInstance().preJoin();
em.joinTransaction();
em.persist(entity);
HibHelper.getInstance().commit();
}

private static Long persistVuln(EntityManager em, String name, String status,
Date devClosed, Date stagingClosed, Date closed) {
Vulnerability v = new Vulnerability();
v.setName(name);
v.setOverall((long) testRiskId);
v.setOpened(new Date());
v.setStatus(status);
v.setDevClosed(devClosed);
v.setStagingClosed(stagingClosed);
v.setClosed(closed);
persist(em, v);
return v.getId();
}

@AfterClass
public static void cleanupFixtures() {
if (emf == null)
return;
EntityManager em = emf.createEntityManager();
try {
remove(em, RiskLevel.class, riskLevelId);
remove(em, Vulnerability.class, openVulnId);
remove(em, Vulnerability.class, devClosedVulnId);
remove(em, Vulnerability.class, stagingClosedVulnId);
remove(em, Vulnerability.class, prodClosedVulnId);
} finally {
em.close();
}
}

private static void remove(EntityManager em, Class<?> clazz, Long id) {
if (id == null)
return;
Object entity = em.find(clazz, id);
if (entity != null) {
HibHelper.getInstance().preJoin();
em.joinTransaction();
em.remove(entity);
HibHelper.getInstance().commit();
}
}

private boolean contains(List<Vulnerability> vulns, String name) {
for (Vulnerability v : vulns) {
if (v.getName() != null && v.getName().startsWith(name))
return true;
}
return false;
}

@Test
public void openVulnsExcludeOnlyProdClosed() {
EntityManager em = emf.createEntityManager();
try {
List<Vulnerability> open = VulnerabilityQueries.getOpenVulns(em);

assertTrue("plain open vuln must be listed", contains(open, "open-" + tag));
assertTrue("dev-closed vuln is still open in prod and must be listed",
contains(open, "dev-" + tag));
assertTrue("staging-closed vuln is still open in prod and must be listed",
contains(open, "staging-" + tag));
assertFalse("prod-closed vuln must not be listed", contains(open, "prod-" + tag));
} finally {
em.close();
}
}
}
Loading