Skip to content

Commit

Permalink
Merge pull request #2 from nscuro/issue-2041-resolve-merge-conflicts
Browse files Browse the repository at this point in the history
Collection projects suggestions and cleanup
  • Loading branch information
rkg-mm authored Dec 9, 2024
2 parents f9769d5 + 111900a commit b840f33
Show file tree
Hide file tree
Showing 9 changed files with 108 additions and 80 deletions.
26 changes: 18 additions & 8 deletions src/main/java/org/dependencytrack/model/Project.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
import com.github.packageurl.MalformedPackageURLException;
import com.github.packageurl.PackageURL;
import io.swagger.v3.oas.annotations.media.Schema;

import org.dependencytrack.parser.cyclonedx.util.ModelConverter;
import org.dependencytrack.persistence.converter.OrganizationalContactsJsonConverter;
import org.dependencytrack.persistence.converter.OrganizationalEntityJsonConverter;
Expand Down Expand Up @@ -104,11 +103,19 @@
}),
@FetchGroup(name = "METRICS_UPDATE", members = {
@Persistent(name = "id"),
@Persistent(name = "parent"),
@Persistent(name = "collectionLogic"),
@Persistent(name = "collectionTag"),
@Persistent(name = "lastInheritedRiskScore"),
@Persistent(name = "uuid")
}),
@FetchGroup(name = "PARENT", members = {
@Persistent(name = "parent")
}),
@FetchGroup(name = "PORTFOLIO_METRICS_UPDATE", members = {
@Persistent(name = "id"),
@Persistent(name = "lastInheritedRiskScore"),
@Persistent(name = "uuid")
})
})
@JsonInclude(JsonInclude.Include.NON_NULL)
Expand All @@ -123,7 +130,8 @@ public enum FetchGroup {
ALL,
METADATA,
METRICS_UPDATE,
PARENT
PARENT,
PORTFOLIO_METRICS_UPDATE
}

@PrimaryKey
Expand Down Expand Up @@ -190,10 +198,9 @@ public enum FetchGroup {
private Classifier classifier;

@Persistent
@Column(name = "COLLECTION_LOGIC", jdbcType = "VARCHAR", allowsNull = "true", defaultValue = "NONE") // New column, must allow nulls on existing databases
@Index(name = "PROJECT_COLLECTION_LOGIC_IDX")
@Column(name = "COLLECTION_LOGIC", jdbcType = "VARCHAR", allowsNull = "true")
@Extension(vendorName = "datanucleus", key = "enum-check-constraint", value = "true")
private ProjectCollectionLogic collectionLogic = ProjectCollectionLogic.NONE;
private ProjectCollectionLogic collectionLogic;

@Persistent(defaultFetchGroup = "true")
@Column(name = "COLLECTION_TAG", allowsNull = "true")
Expand Down Expand Up @@ -405,13 +412,16 @@ public void setClassifier(Classifier classifier) {
this.classifier = classifier;
}


public ProjectCollectionLogic getCollectionLogic() {
return collectionLogic;
return collectionLogic == null
? ProjectCollectionLogic.NONE
: collectionLogic;
}

public void setCollectionLogic(ProjectCollectionLogic collectionLogic) {
this.collectionLogic = collectionLogic;
this.collectionLogic = collectionLogic != ProjectCollectionLogic.NONE
? collectionLogic
: null;
}

public Tag getCollectionTag() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
* by this type.
*
* @author Ralf King
* @since 4.11.0
* @since 4.13.0
*/
public enum ProjectCollectionLogic {
/**
Expand Down
23 changes: 15 additions & 8 deletions src/main/java/org/dependencytrack/model/ProjectMetrics.java
Original file line number Diff line number Diff line change
Expand Up @@ -172,12 +172,12 @@ public class ProjectMetrics implements Serializable {
private Integer policyViolationsOperationalUnaudited;

@Persistent
@Column(name = "COLLECTION_LOGIC", allowsNull = "true") // New column, must allow nulls on existing data bases
@Column(name = "COLLECTION_LOGIC", allowsNull = "true")
private ProjectCollectionLogic collectionLogic;

@Persistent
@Column(name = "COLLECTION_LOGIC_CHANGED", allowsNull = "true") // New column, must allow nulls on existing data bases
private Boolean collectionLogicChanged = false;
@Column(name = "COLLECTION_LOGIC_CHANGED", allowsNull = "false", defaultValue = "false")
private boolean collectionLogicChanged = false;

Check warning on line 180 in src/main/java/org/dependencytrack/model/ProjectMetrics.java

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/main/java/org/dependencytrack/model/ProjectMetrics.java#L180

Avoid using redundant field initializer for 'collectionLogicChanged'

@Persistent
@Column(name = "FIRST_OCCURRENCE", allowsNull = "false")
Expand Down Expand Up @@ -433,16 +433,23 @@ public void setPolicyViolationsOperationalUnaudited(int policyViolationsOperatio
this.policyViolationsOperationalUnaudited = policyViolationsOperationalUnaudited;
}

public ProjectCollectionLogic getCollectionLogic() { return collectionLogic; }
public ProjectCollectionLogic getCollectionLogic() {
return collectionLogic == null
? ProjectCollectionLogic.NONE
: collectionLogic;
}

public void setCollectionLogic(ProjectCollectionLogic collectionLogic) {
// convert old NULL values from DB to NONE
this.collectionLogic = collectionLogic != null ? collectionLogic : ProjectCollectionLogic.NONE;
this.collectionLogic = collectionLogic != ProjectCollectionLogic.NONE
? collectionLogic
: null;
}

public Boolean isCollectionLogicChanged() { return collectionLogicChanged; }
public boolean isCollectionLogicChanged() {
return collectionLogicChanged;
}

public void setCollectionLogicChanged(Boolean collectionLogicChanged) {
public void setCollectionLogicChanged(boolean collectionLogicChanged) {
this.collectionLogicChanged = collectionLogicChanged;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -596,11 +596,6 @@ public Project updateProject(Project transientProject, boolean commitIndex) {
} else {
project.setCollectionTag(null);
}
// Force loading parent. This seems useless but somehow the code block above magically unloads the parent,
// making it missing in the API response. Following line enforces it to be available again.
// For reference see following Unit Test which would fail without this:
// org.dependencytrack.resources.v1.ProjectResourceTest.patchProjectParentTest
project.getParent();

return persist(project);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ private List<Project> fetchNextActiveProjectsBatch(final PersistenceManager pm,

// NB: Set fetch group on PM level to avoid fields of the default fetch group from being loaded.
try (var ignoredPersistenceCustomization = new ScopedCustomization(pm)
.withFetchGroup(Project.FetchGroup.METRICS_UPDATE.name())) {
.withFetchGroup(Project.FetchGroup.PORTFOLIO_METRICS_UPDATE.name())) {
return List.copyOf(query.executeList());
} finally {
query.closeAll();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,13 @@ public void inform(final Event e) {
}
}

private void updateMetrics(final UUID uuid) throws Exception {
private void updateMetrics(final UUID uuid) {
final var counters = new Counters();

try (final QueryManager qm = new QueryManager()) {
final PersistenceManager pm = qm.getPersistenceManager();

final Project project = qm.getObjectByUuid(Project.class, uuid, List.of(Project.FetchGroup.METRICS_UPDATE.name()));
final Project project = fetchProject(pm, uuid);
if (project == null) {
throw new NoSuchElementException("Project " + uuid + " does not exist");
}
Expand Down Expand Up @@ -115,7 +115,7 @@ private void updateMetrics(final UUID uuid) throws Exception {
}
}

private void updateRegularProjectMetrics(final Project project, final PersistenceManager pm, final Counters counters) throws Exception {
private void updateRegularProjectMetrics(final Project project, final PersistenceManager pm, final Counters counters) {
final UUID uuid = project.getUuid();

LOGGER.debug("Fetching first components page for project " + uuid);
Expand Down Expand Up @@ -240,13 +240,10 @@ private void updateAggregateDirectChildrenWithTagCollectionMetrics(final Project
}

private void updateLatestVersionChildrenCollectionMetrics(final Project project, final PersistenceManager pm, final Counters counters) {
LOGGER.warn("Collection logic LATEST_VERSION_CHILDREN not yet implemented. Waiting for https://github.com/DependencyTrack/dependency-track/issues/4148");
/*
TODO: Create Test case in ProjectMetricsUpdateTaskTest*/
LOGGER.debug("Fetching metrics of children of collection project " + project.getUuid() +
" using collection logic " + project.getCollectionLogic());

Query subQuery = pm.newQuery(ProjectMetrics.class);
Query<ProjectMetrics> subQuery = pm.newQuery(ProjectMetrics.class);
subQuery.setFilter("project == :project");
subQuery.setResult("max(lastOccurrence)");

Expand All @@ -266,6 +263,20 @@ private void updateLatestVersionChildrenCollectionMetrics(final Project project,
}
}

private Project fetchProject(final PersistenceManager pm, final UUID uuid) {
final Query<Project> query = pm.newQuery(Project.class);
query.setFilter("uuid == :uuid");
query.setParameters(uuid);

// NB: Set fetch group on PM level to avoid fields of the default fetch group from being loaded.
try (var ignoredPersistenceCustomization = new ScopedCustomization(pm)
.withFetchGroup(Project.FetchGroup.METRICS_UPDATE.name())) {
return query.executeUnique();
} finally {
query.closeAll();
}
}

private List<Component> fetchNextComponentsPage(final PersistenceManager pm, final Project project, final Long lastId) {
final Query<Component> query = pm.newQuery(Component.class);
if (lastId == null) {
Expand Down Expand Up @@ -293,7 +304,7 @@ private void addToCounters(Counters counters, ProjectMetrics projectMetrics) {
counters.medium += projectMetrics.getMedium();
counters.low += projectMetrics.getLow();
counters.unassigned += projectMetrics.getUnassigned();
counters.vulnerabilities += projectMetrics.getVulnerabilities();
counters.vulnerabilities += Math.toIntExact(projectMetrics.getVulnerabilities());

counters.findingsTotal += projectMetrics.getFindingsTotal();
counters.findingsAudited += projectMetrics.getFindingsAudited();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ class UpgradeItems {
UPGRADE_ITEMS.add(org.dependencytrack.upgrade.v4110.v4110Updater.class);
UPGRADE_ITEMS.add(org.dependencytrack.upgrade.v4120.v4120Updater.class);
UPGRADE_ITEMS.add(org.dependencytrack.upgrade.v4122.v4122Updater.class);
UPGRADE_ITEMS.add(org.dependencytrack.upgrade.v4130.v4130Updater.class);
}

static List<Class<? extends UpgradeItem>> getUpgradeItems() {
Expand Down
48 changes: 0 additions & 48 deletions src/main/java/org/dependencytrack/upgrade/v4130/v4130Updater.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -1221,6 +1221,60 @@ public void updateProjectAsLatestWithACLAndNoAccessTest() {
Assert.assertTrue(qm.getProject(noAccessLatestProject.getName(), noAccessLatestProject.getVersion()).isLatest());
}

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

final var component = new Component();
component.setProject(project);
component.setName("acme-lib");
qm.persist(component);

final Response response = jersey.target(V1_PROJECT)
.request()
.header(X_API_KEY, apiKey)
.post(Entity.json(/* language=JSON */ """
{
"uuid": "%s",
"name": "acme-app",
"collectionLogic": "AGGREGATE_DIRECT_CHILDREN"
}
""".formatted(project.getUuid())));
assertThat(response.getStatus()).isEqualTo(409);
assertThat(getPlainTextBody(response)).isEqualTo("""
Project cannot be made a collection project while it has \
components or services!""");
}

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

final var service = new ServiceComponent();
service.setProject(project);
service.setName("some-service");
qm.persist(service);

final Response response = jersey.target(V1_PROJECT)
.request()
.header(X_API_KEY, apiKey)
.post(Entity.json(/* language=JSON */ """
{
"uuid": "%s",
"name": "acme-app",
"collectionLogic": "AGGREGATE_DIRECT_CHILDREN"
}
""".formatted(project.getUuid())));
assertThat(response.getStatus()).isEqualTo(409);
assertThat(getPlainTextBody(response)).isEqualTo("""
Project cannot be made a collection project while it has \
components or services!""");
}

@Test
public void deleteProjectTest() {
Project project = qm.createProject("ABC", null, "1.0", null, null, null, true, false);
Expand Down

0 comments on commit b840f33

Please sign in to comment.