Skip to content

Commit

Permalink
Integrity analysis if enabled (#399)
Browse files Browse the repository at this point in the history
  • Loading branch information
VithikaS authored Oct 27, 2023
1 parent cf1a484 commit 4e15bd6
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import alpine.Config;
import alpine.common.logging.Logger;
import org.datanucleus.util.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.dependencytrack.common.ConfigKey;
import org.dependencytrack.model.Component;
import org.dependencytrack.model.IntegrityAnalysis;
Expand All @@ -12,6 +12,7 @@
import org.hyades.proto.repometaanalysis.v1.AnalysisResult;

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

import static org.dependencytrack.model.IntegrityMatchStatus.COMPONENT_MISSING_HASH;
import static org.dependencytrack.model.IntegrityMatchStatus.COMPONENT_MISSING_HASH_AND_MATCH_UNKNOWN;
Expand All @@ -28,8 +29,16 @@ public static void performIntegrityCheck(final IntegrityMetaComponent integrityM
LOGGER.debug("Integrity check is disabled");
return;
}
if (StringUtils.isEmpty(result.getComponent().getUuid())) {
LOGGER.info("Result received on topic does not have component uuid, integrity check cannot be performed");
//if integritymeta is in result with hashses but component uuid is not present, result has integrity data for existing
// components. Get components from database and perform integrity check
if (result.hasIntegrityMeta() && StringUtils.isBlank(result.getComponent().getUuid())) {
if(integrityMetaComponent != null) {
List<Component> componentList = qm.getComponentsByPurl(result.getComponent().getPurl());
for(Component component : componentList) {
LOGGER.debug("calculate integrity for component : " + component.getUuid());
calculateIntegrityResult(integrityMetaComponent, component, qm);
}
}
return;
}
//check if the object is not null
Expand All @@ -38,9 +47,30 @@ public static void performIntegrityCheck(final IntegrityMetaComponent integrityM
LOGGER.info("Component is not present in database for which Integrity Check is performed");
return;
}
calculateIntegrityResult(integrityMetaComponent, component, qm);
}

private static IntegrityMatchStatus checkHash(String metadataHash, String componentHash) {
if (StringUtils.isBlank(metadataHash) && StringUtils.isBlank(componentHash)) {
return COMPONENT_MISSING_HASH_AND_MATCH_UNKNOWN;
}
if (StringUtils.isBlank(metadataHash)) {
return HASH_MATCH_UNKNOWN;
}
if (StringUtils.isBlank(componentHash)) {
return COMPONENT_MISSING_HASH;
}
return componentHash.equals(metadataHash) ? HASH_MATCH_PASSED : HASH_MATCH_FAILED;
}

private static void calculateIntegrityResult(final IntegrityMetaComponent integrityMetaComponent, final Component component, final QueryManager qm) {
//if integritymetacomponent is null, try to get it from db
//it could be that integrity metadata is already in db
IntegrityMetaComponent metadata = integrityMetaComponent == null ? qm.getIntegrityMetaComponent(result.getComponent().getPurl().toString()) : integrityMetaComponent;
IntegrityMetaComponent metadata = integrityMetaComponent == null ? qm.getIntegrityMetaComponent(component.getPurl().toString()) : integrityMetaComponent;
if(metadata == null) {
LOGGER.info("Integrity metadata is null in result and db. Cannot perform integrity analysis");
return;
}
IntegrityMatchStatus md5Status = checkHash(metadata.getMd5(), component.getMd5());
IntegrityMatchStatus sha1Status = checkHash(metadata.getSha1(), component.getSha1());
IntegrityMatchStatus sha256Status = checkHash(metadata.getSha256(), component.getSha256());
Expand All @@ -60,19 +90,6 @@ public static void performIntegrityCheck(final IntegrityMetaComponent integrityM
qm.persist(integrityAnalysis);
}

private static IntegrityMatchStatus checkHash(String metadataHash, String componentHash) {
if (StringUtils.isEmpty(metadataHash) && StringUtils.isEmpty(componentHash)) {
return COMPONENT_MISSING_HASH_AND_MATCH_UNKNOWN;
}
if (StringUtils.isEmpty(metadataHash)) {
return HASH_MATCH_UNKNOWN;
}
if (StringUtils.isEmpty(componentHash)) {
return COMPONENT_MISSING_HASH;
}
return componentHash.equals(metadataHash) ? HASH_MATCH_PASSED : HASH_MATCH_FAILED;
}

private static IntegrityMatchStatus calculateIntegrityCheckStatus(IntegrityMatchStatus md5Status, IntegrityMatchStatus sha1Status, IntegrityMatchStatus sha256Status, IntegrityMatchStatus sha512Status) {
if (md5Status == COMPONENT_MISSING_HASH_AND_MATCH_UNKNOWN && sha1Status == COMPONENT_MISSING_HASH_AND_MATCH_UNKNOWN && sha256Status == COMPONENT_MISSING_HASH_AND_MATCH_UNKNOWN && sha512Status == COMPONENT_MISSING_HASH_AND_MATCH_UNKNOWN) {
return COMPONENT_MISSING_HASH_AND_MATCH_UNKNOWN;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -814,4 +814,13 @@ private void getDirectDependenciesForPathDependencies(Map<String, Component> dep
}
dependencyGraph.putAll(addToDependencyGraph);
}

public List<Component> getComponentsByPurl(String purl) {
try(final Query<Component> query = pm.newQuery(Component.class, "purl == :purl")) {
query.setParameters(purl);
return List.copyOf(query.executeResultList(Component.class));
} catch(Exception exception) {
throw new RuntimeException(exception);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1878,4 +1878,8 @@ public ComponentMetaInformation getMetaInformation(UUID uuid) {
}
return null;
}

public List<Component> getComponentsByPurl(String purl) {
return getComponentQueryManager().getComponentsByPurl(purl);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ public void testIntegrityCheckWithDataInDb() {
}

@Test
public void testIntegrityCheckWillNotBeDoneIfComponentUuidIsMissing() {
public void testIntegrityCheckWillNotBeDoneIfComponentUuidAndIntegrityDataIsMissing() {
// Create an active project with one component.
final var projectA = qm.createProject("acme-app-a", null, "1.0.0", null, null, null, true, false);
final var componentProjectA = new Component();
Expand Down Expand Up @@ -356,6 +356,48 @@ public void testIntegrityCheckWillNotBeDoneIfComponentUuidIsMissing() {
assertThat(analysis).isNull();
}

@Test
public void testIntegrityIfResultHasIntegrityDataAndComponentUuidIsMissing() {
// Create an active project with one component.
final var projectA = qm.createProject("acme-app-a", null, "1.0.0", null, null, null, true, false);
final var componentProjectA = new Component();
UUID uuid = UUID.randomUUID();
componentProjectA.setProject(projectA);
componentProjectA.setName("acme-lib-a");
componentProjectA.setVersion("1.0.1");
componentProjectA.setPurl("pkg:maven/foo/[email protected]");
componentProjectA.setPurlCoordinates("pkg:maven/foo/[email protected]");
componentProjectA.setUuid(uuid);
componentProjectA.setMd5("098f6bcd4621d373cade4e832627b4f6");
componentProjectA.setSha1("a94a8fe5ccb19ba61c4c0873d391e987982fbbd3");

Component c = qm.persist(componentProjectA);
var integrityMetaComponent = new IntegrityMetaComponent();
integrityMetaComponent.setPurl("pkg:maven/foo/[email protected]");
integrityMetaComponent.setStatus(FetchStatus.IN_PROGRESS);
Date date = Date.from(Instant.now().minus(15, ChronoUnit.MINUTES));
integrityMetaComponent.setLastFetch(date);
qm.persist(integrityMetaComponent);

final var result = AnalysisResult.newBuilder()
.setComponent(org.hyades.proto.repometaanalysis.v1.Component.newBuilder()
.setPurl("pkg:maven/foo/[email protected]"))
.setIntegrityMeta(IntegrityMeta.newBuilder()
.setMd5("098f6bcd4621d373cade4e832627b4f6")
.setSha1("a94a8fe5ccb19ba61c4c0873d391e987982fbbd3")
.build())
//component uuid has not been set
.build();

inputTopic.pipeInput(new TestRecord<>("pkg:maven/foo/[email protected]", result, Instant.now()));

IntegrityAnalysis analysis = qm.getIntegrityAnalysisByComponentUuid(c.getUuid());
assertThat(analysis).isNotNull();
assertThat(analysis.getComponent()).isEqualTo(c);
assertThat(analysis.getIntegrityCheckStatus()).isEqualTo(IntegrityMatchStatus.HASH_MATCH_PASSED);
}


@Test
public void testIntegrityCheckWillNotBeDoneIfComponentIsNotInDb() {

Expand Down Expand Up @@ -612,7 +654,6 @@ public void processBothMetaModelAndIntegrityMeta() {

inputTopic.pipeInput("pkg:maven/foo/bar", result);
qm.getPersistenceManager().refresh(integrityMetaComponent);
qm.getPersistenceManager().refresh(integrityMetaComponent);
final RepositoryMetaComponent metaComponent =
qm.getRepositoryMetaComponent(RepositoryType.MAVEN, "foo", "bar");
assertThat(metaComponent).isNotNull();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import javax.jdo.JDOObjectNotFoundException;
import java.util.Date;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
Expand Down Expand Up @@ -105,4 +106,45 @@ public void recursivelyDeleteTest() {
assertThatNoException().isThrownBy(() -> qm.getObjectById(PolicyCondition.class, policyCondition.getId()));
assertThatNoException().isThrownBy(() -> qm.getObjectById(Policy.class, policy.getId()));
}

@Test
public void testGetComponentsByPurl() {
final var project = new Project();
project.setName("acme-app");
project.setVersion("1.0.0");
qm.persist(project);

final var component1 = new Component();
component1.setProject(project);
component1.setName("acme-lib-a");
component1.setVersion("1.0.1");
component1.setPurl("pkg:maven/foo/[email protected]");
component1.setPurlCoordinates("pkg:maven/foo/[email protected]");
component1.setMd5("098f6bcd4621d373cade4e832627b4f6");
component1.setSha1("a94a8fe5ccb19ba61c4c0873d391e987982fbbd3");
qm.persist(component1);

final var component2 = new Component();
component2.setProject(project);
component2.setProject(project);
component2.setName("acme-lib");
component2.setVersion("1.0.1");
component2.setPurl("pkg:maven/foo/[email protected]");
component2.setPurlCoordinates("pkg:maven/foo/[email protected]");
component2.setMd5("098f6bcd4621d373cade4e832627b4f6");
component2.setSha1("a94a8fe5ccb19ba61c4c0873d391e987982fbbd3");
qm.persist(component2);

List<Component> components = qm.getComponentsByPurl("pkg:maven/foo/[email protected]");
assertThat(components).isNotNull();
assertThat(components).hasSize(2);
assertThat(components).satisfiesExactlyInAnyOrder(component -> {
assertThat(component.getMd5()).isEqualTo("098f6bcd4621d373cade4e832627b4f6");
assertThat(component.getSha1()).isEqualTo("a94a8fe5ccb19ba61c4c0873d391e987982fbbd3");
},
component -> {
assertThat(component.getMd5()).isEqualTo("098f6bcd4621d373cade4e832627b4f6");
assertThat(component.getSha1()).isEqualTo("a94a8fe5ccb19ba61c4c0873d391e987982fbbd3");
});
}
}

0 comments on commit 4e15bd6

Please sign in to comment.