Skip to content
Open
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
16 changes: 16 additions & 0 deletions docs/_docs/datasources/composer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
title: Composer Advisories
category: Datasources
chapter: 4
order: 11
---

[Composer Advisories](https://blog.packagist.com/discover-security-advisories-with-composers-audit-command/) (PKSA) is a database of CVEs and other vulnerabilities affecting the Composer packages. Advisories may or may not be documented in the [National Vulnerability Database]({{ site.baseurl }}{% link _docs/datasources/nvd.md %}).

Dependency-Track integrates with Composer by mirroring advisories via each repositories [Packagist API](https://packagist.org/apidoc).
The mirroring (and alias synchronization) can be enabled/disabled [per repository]({{ site.baseurl }}{% link _docs/datasources/repositories.md %}).
The mirror is refreshed daily, or upon restart of the Dependency-Track instance.

![Composer Advisories Configuration](../../images/screenshots/composer-repository-configuration.png)


2 changes: 1 addition & 1 deletion docs/_docs/datasources/repositories.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,4 @@ for information on Package URL and the various ways it is used throughout Depend

For GitHub repositories (`github.com` per default), the username should be the GitHub account's username,
and the password should be a [personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token)
(PAT) with public access (no additional scopes).
(PAT) with public access (no additional scopes).
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* This file is part of Dependency-Track.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
* Copyright (c) OWASP Foundation. All Rights Reserved.
*/
package org.dependencytrack.event;

import java.util.UUID;

import alpine.event.framework.SingletonCapableEvent;

/**
* Defines an event used to start a mirror of the NVD.
*
* @author Valentijn Scholten
* @since 4.13.0
*/
public class ComposerAdvisoryMirrorEvent extends SingletonCapableEvent {

private static final UUID CHAIN_IDENTIFIER = UUID.fromString("62710465-3117-4cc1-ad9a-d1dce721aa86");

public ComposerAdvisoryMirrorEvent() {
setChainIdentifier(CHAIN_IDENTIFIER);
setSingleton(true);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import org.dependencytrack.tasks.metrics.PortfolioMetricsUpdateTask;
import org.dependencytrack.tasks.metrics.ProjectMetricsUpdateTask;
import org.dependencytrack.tasks.metrics.VulnerabilityMetricsUpdateTask;
import org.dependencytrack.tasks.repositories.ComposerAdvisoryMirrorTask;
import org.dependencytrack.tasks.repositories.RepositoryMetaAnalyzerTask;
import org.dependencytrack.tasks.scanners.InternalAnalysisTask;
import org.dependencytrack.tasks.scanners.OssIndexAnalysisTask;
Expand Down Expand Up @@ -99,6 +100,7 @@ public void contextInitialized(final ServletContextEvent event) {
EVENT_SERVICE.subscribe(GitHubAdvisoryMirrorEvent.class, GitHubAdvisoryMirrorTask.class);
EVENT_SERVICE.subscribe(OsvMirrorEvent.class, OsvDownloadTask.class);
EVENT_SERVICE.subscribe(VulnDbSyncEvent.class, VulnDbSyncTask.class);
EVENT_SERVICE.subscribe(ComposerAdvisoryMirrorEvent.class, ComposerAdvisoryMirrorTask.class);
EVENT_SERVICE.subscribe(VulnDbAnalysisEvent.class, VulnDbAnalysisTask.class);
EVENT_SERVICE.subscribe(VulnerabilityAnalysisEvent.class, VulnerabilityAnalysisTask.class);
EVENT_SERVICE.subscribe(PortfolioVulnerabilityAnalysisEvent.class, VulnerabilityAnalysisTask.class);
Expand Down Expand Up @@ -141,6 +143,7 @@ public void contextDestroyed(final ServletContextEvent event) {
EVENT_SERVICE.unsubscribe(InternalAnalysisTask.class);
EVENT_SERVICE.unsubscribe(OssIndexAnalysisTask.class);
EVENT_SERVICE.unsubscribe(GitHubAdvisoryMirrorTask.class);
EVENT_SERVICE.unsubscribe(ComposerAdvisoryMirrorTask.class);
EVENT_SERVICE.unsubscribe(OsvDownloadTask.class);
EVENT_SERVICE.unsubscribe(VulnDbSyncTask.class);
EVENT_SERVICE.unsubscribe(VulnDbAnalysisTask.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,11 @@ public enum ConfigPropertyConstants {
NOTIFICATION_TEMPLATE_BASE_DIR("notification", "template.baseDir", SystemUtils.getEnvironmentVariable("DEFAULT_TEMPLATES_OVERRIDE_BASE_DIRECTORY", System.getProperty("user.home")), PropertyType.STRING, "The base directory to use when searching for notification templates"),
NOTIFICATION_TEMPLATE_DEFAULT_OVERRIDE_ENABLED("notification", "template.default.override.enabled", SystemUtils.getEnvironmentVariable("DEFAULT_TEMPLATES_OVERRIDE_ENABLED", "false"), PropertyType.BOOLEAN, "Flag to enable/disable override of default notification templates"),
TASK_SCHEDULER_LDAP_SYNC_CADENCE("task-scheduler", "ldap.sync.cadence", "6", PropertyType.INTEGER, "Sync cadence (in hours) for LDAP"),
TASK_SCHEDULER_GHSA_MIRROR_CADENCE("task-scheduler", "ghsa.mirror.cadence", "24", PropertyType.INTEGER, "Mirror cadence (in hours) for Github Security Advisories"),
TASK_SCHEDULER_GHSA_MIRROR_CADENCE("task-scheduler", "ghsa.mirror.cadence", "1", PropertyType.INTEGER, "Mirror cadence (in hours) for Github Security Advisories"),
TASK_SCHEDULER_OSV_MIRROR_CADENCE("task-scheduler", "osv.mirror.cadence", "24", PropertyType.INTEGER, "Mirror cadence (in hours) for OSV database"),
TASK_SCHEDULER_NIST_MIRROR_CADENCE("task-scheduler", "nist.mirror.cadence", "24", PropertyType.INTEGER, "Mirror cadence (in hours) for NVD database"),
TASK_SCHEDULER_VULNDB_MIRROR_CADENCE("task-scheduler", "vulndb.mirror.cadence", "24", PropertyType.INTEGER, "Mirror cadence (in hours) for VulnDB database"),
TASK_SCHEDULER_COMPOSER_MIRROR_CADENCE("task-scheduler", "composer.mirror.cadencee", "24", PropertyType.INTEGER, "Mirror cadence (in hours) for Vulnerability mirroring of Composer repositories"),
TASK_SCHEDULER_PORTFOLIO_METRICS_UPDATE_CADENCE("task-scheduler", "portfolio.metrics.update.cadence", "1", PropertyType.INTEGER, "Update cadence (in hours) for portfolio metrics"),
TASK_SCHEDULER_VULNERABILITY_METRICS_UPDATE_CADENCE("task-scheduler", "vulnerability.metrics.update.cadence", "1", PropertyType.INTEGER, "Update cadence (in hours) for vulnerability metrics"),
TASK_SCHEDULER_PORTFOLIO_VULNERABILITY_ANALYSIS_CADENCE("task-scheduler", "portfolio.vulnerability.analysis.cadence", "24", PropertyType.INTEGER, "Launch cadence (in hours) for portfolio vulnerability analysis"),
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/org/dependencytrack/model/Finding.java
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,12 @@ public void addVulnerabilityAliases(List<VulnerabilityAlias> aliases) {
if (alias.getVulnDbId() != null && !alias.getVulnDbId().isBlank()) {
map.put("vulnDbId", alias.getVulnDbId());
}
if (alias.getDrupalId() != null && !alias.getDrupalId().isBlank()) {
map.put("drupalId", alias.getDrupalId());
}
if (alias.getComposerId() != null && !alias.getComposerId().isBlank()) {
map.put("composerId", alias.getComposerId());
}
uniqueAliases.add(map);
}
vulnerability.put("aliases",uniqueAliases);
Expand Down
26 changes: 26 additions & 0 deletions src/main/java/org/dependencytrack/model/Repository.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ public class Repository implements Serializable {
@JsonDeserialize(using = TrimmedStringDeserializer.class)
private String identifier;

@Persistent
@Column(name = "DESCRIPTION")
@JsonDeserialize(using = TrimmedStringDeserializer.class)
private String description;

@Persistent
@Column(name = "URL")
@NotBlank
Expand Down Expand Up @@ -100,6 +105,11 @@ public class Repository implements Serializable {
@Column(name = "PASSWORD")
private String password;

@Persistent
@Column(name = "CONFIG", jdbcType = "CLOB")
@JsonDeserialize(using = TrimmedStringDeserializer.class)
private String config;

@Persistent(customValueStrategy = "uuid")
@Index(name = "REPOSITORY_UUID_IDX") // Cannot be @Unique. Microsoft SQL Server throws an exception
@Column(name = "UUID", jdbcType = "VARCHAR", length = 36, allowsNull = "true")
Expand Down Expand Up @@ -131,6 +141,14 @@ public void setIdentifier(String identifier) {
this.identifier = identifier;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public String getUrl() {
return url;
}
Expand Down Expand Up @@ -189,6 +207,14 @@ public void setPassword(String password) {
this.password = password;
}

public String getConfig() {
return config;
}

public void setConfig(String config) {
this.config = config;
}

public UUID getUuid() {
return uuid;
}
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/org/dependencytrack/model/Vulnerability.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;

import org.apache.commons.lang3.StringUtils;
import org.dependencytrack.parser.common.resolver.CweResolver;
import org.dependencytrack.persistence.CollectionIntegerConverter;
import org.dependencytrack.resources.v1.serializers.CweDeserializer;
Expand Down Expand Up @@ -111,19 +113,29 @@ public enum Source {
OSV, // Google OSV Advisories
SNYK, // Snyk
TRIVY, // Trivy
COMPOSER, // Composer (Packagist)
DRUPAL, // Drupal
UNKNOWN; // Unknown vulnerability sources

public static boolean isKnownSource(String source) {
return Arrays.stream(values()).anyMatch(enumSource -> enumSource.name().equalsIgnoreCase(source));
}

public static Source resolve(String id) {
if (StringUtils.isBlank(id)) {
return UNKNOWN;
}

if (id.startsWith("CVE-")){
return NVD;
} else if (id.startsWith("GHSA-")){
return GITHUB;
} else if (id.startsWith("OSV-")){
return OSV;
} else if (id.startsWith("SA-CORE-") || id.startsWith("SA-CONTRIB")){
return DRUPAL;
} else if (id.startsWith("PKSA-")){
return COMPOSER;
} else if (id.startsWith("SNYK-")){
return SNYK;
}
Expand Down
101 changes: 100 additions & 1 deletion src/main/java/org/dependencytrack/model/VulnerabilityAlias.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
import javax.jdo.annotations.Unique;

import org.apache.commons.lang3.StringUtils;

import java.io.Serializable;
import java.util.Arrays;
import java.util.Map;
Expand Down Expand Up @@ -111,6 +114,20 @@ public class VulnerabilityAlias implements Serializable {
@Pattern(regexp = RegexSequence.Definition.PRINTABLE_CHARS_PLUS, message = "The vulnDbId field may only contain printable characters")
private String vulnDbId;

@Persistent
@Column(name = "DRUPAL_ID")
@Index(name = "VULNERABILITYALIAS_DRUPAL_ID_IDX")
@JsonDeserialize(using = TrimmedStringDeserializer.class)
@Pattern(regexp = RegexSequence.Definition.PRINTABLE_CHARS_PLUS, message = "The drupalId field may only contain printable characters")
private String drupalId;

@Persistent
@Column(name = "COMPOSER_ID")
@Index(name = "VULNERABILITYALIAS_COMPOSER_ID_IDX")
@JsonDeserialize(using = TrimmedStringDeserializer.class)
@Pattern(regexp = RegexSequence.Definition.PRINTABLE_CHARS_PLUS, message = "The composerId field may only contain printable characters")
private String composerId;

@Persistent(customValueStrategy = "uuid")
@Unique(name = "VULNERABILITYALIAS_UUID_IDX")
@Column(name = "UUID", jdbcType = "VARCHAR", length = 36, allowsNull = "false")
Expand Down Expand Up @@ -185,6 +202,22 @@ public void setVulnDbId(String vulnDbId) {
this.vulnDbId = vulnDbId;
}

public String getDrupalId() {
return drupalId;
}

public void setDrupalId(String drupalId) {
this.drupalId = drupalId;
}

public String getComposerId() {
return composerId;
}

public void setComposerId(String composerId) {
this.composerId = composerId;
}

public UUID getUuid() {
return uuid;
}
Expand All @@ -202,6 +235,8 @@ private String getBySource(final Vulnerability.Source source) {
case OSV -> getOsvId();
case SNYK -> getSnykId();
case VULNDB -> getVulnDbId();
case DRUPAL -> getDrupalId();
case COMPOSER -> getComposerId();
default -> null;
};
}
Expand All @@ -224,6 +259,8 @@ public void copyFieldsFrom(VulnerabilityAlias other) {
gsdId = firstNonNull(other.gsdId, gsdId);
vulnDbId = firstNonNull(other.vulnDbId, vulnDbId);
internalId = firstNonNull(other.internalId, internalId);
drupalId = firstNonNull(other.drupalId, drupalId);
composerId = firstNonNull(other.composerId, composerId);
}

private static String firstNonNull(String first, String second) {
Expand Down Expand Up @@ -263,10 +300,71 @@ public int computeMatches(final VulnerabilityAlias other) {
if (this.getVulnDbId() != null && this.getVulnDbId().equals(other.getVulnDbId())) {
matches++;
}
if (this.getDrupalId() != null && this.getDrupalId().equals(other.getDrupalId())) {
matches++;
}
if (this.getComposerId() != null && this.getComposerId().equals(other.getComposerId())) {
matches++;
}

return matches;
}

/**
* Compute how many identifiers are set for this alias record
*
* @return Number of identifiers set
*/
public int countIdentifiers() {
var count = 0;
count += this.getCveId() != null ? 1 : 0;
count += this.getGhsaId() != null ? 1 : 0;
count += this.getGsdId() != null ? 1 : 0;
count += this.getOsvId() != null ? 1 : 0;
count += this.getSnykId() != null ? 1 : 0;
count += this.getSonatypeId() != null ? 1 : 0;
count += this.getVulnDbId() != null ? 1 : 0;
count += this.getDrupalId() != null ? 1 : 0;
count += this.getComposerId() != null ? 1 : 0;
return count;
}

public boolean setAliasFromVulnId(String vulnId) {
if (StringUtils.isBlank(vulnId)) return false;

if (vulnId.startsWith("GHSA") && this.getGhsaId() == null) {
this.setGhsaId(vulnId);
return true;
}
if (vulnId.startsWith("CVE") && this.getCveId() == null) {
this.setCveId(vulnId);
return true;
}
if ((vulnId.startsWith("SA-CORE") || vulnId.startsWith("SA-CONTRIB")) && this.getDrupalId() == null) {
this.setDrupalId(vulnId);
return true;
}
if (vulnId.startsWith("OSSINDEX") && this.getSonatypeId() == null) {
this.setSonatypeId(vulnId);
return true;
}
if (vulnId.startsWith("SNYK") && this.getSnykId() == null) {
this.setSnykId(vulnId);
return true;
}
if (vulnId.startsWith("GSD") && this.getGsdId() == null) {
this.setGsdId(vulnId);
return true;
}
if (vulnId.startsWith("PKSA") && this.getComposerId() == null) {
this.setComposerId(vulnId);
return true;
}

return false;
}


@Override
public String toString() {
return "VulnerabilityAlias{" +
Expand All @@ -279,8 +377,9 @@ public String toString() {
", snykId='" + snykId + '\'' +
", gsdId='" + gsdId + '\'' +
", vulnDbId='" + vulnDbId + '\'' +
", composerId='" + composerId + '\'' +
", drupalId='" + drupalId + '\'' +
", uuid=" + uuid +
'}';
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public static class Title {
public static final String NOTIFICATION_TEST = "Notification Test";
public static final String NVD_MIRROR = "NVD Mirroring";
public static final String GITHUB_ADVISORY_MIRROR = "GitHub Advisory Mirroring";
public static final String COMPOSER_ADVISORY_MIRROR = "Composer Advisory Mirroring";
public static final String EPSS_MIRROR = "EPSS Mirroring";
public static final String NPM_ADVISORY_MIRROR = "NPM Advisory Mirroring";
public static final String VULNDB_MIRROR = "VulnDB Mirroring";
Expand Down
Loading