From 02f66d6569bf2664a9091e5ca932102cad842eba Mon Sep 17 00:00:00 2001
From: ManjunathMS35
Date: Wed, 17 Aug 2022 09:55:23 +0200
Subject: [PATCH] Use Snyk as data provider (#860)
Fixes #717
---
.../fosstars/advice/oss/SnykAdvisor.java | 43 ++++
.../fosstars/data/DataProviderSelector.java | 2 +
.../AbstractDependencyScanDataProvider.java | 140 ++++++++++++
.../data/github/HasExecutableBinaries.java | 2 -
.../data/github/PackageManagement.java | 4 +
.../fosstars/data/github/UsesDependabot.java | 127 +----------
.../fosstars/data/github/UsesSnyk.java | 106 +++++++++
.../oss/phosphor/fosstars/model/Score.java | 10 +
.../model/feature/oss/OssFeatures.java | 23 ++
.../model/score/oss/DependabotScore.java | 2 +-
.../model/score/oss/DependencyScanScore.java | 23 +-
.../oss/ProjectSecurityAwarenessScore.java | 6 +-
.../score/oss/SnykDependencyScanScore.java | 114 ++++++++++
.../fosstars/model/value/PackageManager.java | 2 +-
.../fosstars/tool/format/CommonFormatter.java | 7 +
.../fosstars/util/Deserialization.java | 2 +
.../fosstars/advice/oss/OssAdvice.yml | 6 +
.../sap/oss/phosphor/fosstars/TestUtils.java | 3 +
.../advice/oss/BanditAdvisorTest.java | 3 -
.../fosstars/advice/oss/SnykAdvisorTest.java | 73 +++++++
.../CodeOfConductGuidelineInfoTest.java | 2 -
.../fosstars/data/github/UsesSnykTest.java | 202 ++++++++++++++++++
.../score/oss/DependencyScanScoreTest.java | 4 +-
.../model/score/oss/OssSecurityScoreTest.java | 2 +
.../oss/SnykDependencyScanScoreTest.java | 64 ++++++
...ssSecurityRatingMarkdownFormatterTest.java | 2 +
.../tool/format/PrettyPrinterTest.java | 2 +
.../OssArtifactSecurityRatingTestVectors.yml | 9 +
.../oss/OssSecurityRatingTestVectors.yml | 9 +
.../score/oss/DependabotScoreTestVectors.yml | 4 +-
.../oss/DependencyScanScoreTestVectors.yml | 15 +-
...ojectSecurityAwarenessScoreTestVectors.yml | 5 +
.../SnykDependencyScanScoreTestVectors.yml | 152 +++++++++++++
...veryAndSecurityTestingScoreTestVectors.yml | 9 +
src/test/shell/tool/github/lib.sh | 2 +
35 files changed, 1043 insertions(+), 138 deletions(-)
create mode 100644 src/main/java/com/sap/oss/phosphor/fosstars/advice/oss/SnykAdvisor.java
create mode 100644 src/main/java/com/sap/oss/phosphor/fosstars/data/github/AbstractDependencyScanDataProvider.java
create mode 100644 src/main/java/com/sap/oss/phosphor/fosstars/data/github/UsesSnyk.java
create mode 100644 src/main/java/com/sap/oss/phosphor/fosstars/model/score/oss/SnykDependencyScanScore.java
create mode 100644 src/test/java/com/sap/oss/phosphor/fosstars/advice/oss/SnykAdvisorTest.java
create mode 100644 src/test/java/com/sap/oss/phosphor/fosstars/data/github/UsesSnykTest.java
create mode 100644 src/test/java/com/sap/oss/phosphor/fosstars/model/score/oss/SnykDependencyScanScoreTest.java
create mode 100644 src/test/resources/com/sap/oss/phosphor/fosstars/model/score/oss/SnykDependencyScanScoreTestVectors.yml
diff --git a/src/main/java/com/sap/oss/phosphor/fosstars/advice/oss/SnykAdvisor.java b/src/main/java/com/sap/oss/phosphor/fosstars/advice/oss/SnykAdvisor.java
new file mode 100644
index 000000000..e5485a654
--- /dev/null
+++ b/src/main/java/com/sap/oss/phosphor/fosstars/advice/oss/SnykAdvisor.java
@@ -0,0 +1,43 @@
+package com.sap.oss.phosphor.fosstars.advice.oss;
+
+import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_SNYK;
+
+import com.sap.oss.phosphor.fosstars.advice.Advice;
+import com.sap.oss.phosphor.fosstars.advice.oss.OssAdviceContentYamlStorage.OssAdviceContext;
+import com.sap.oss.phosphor.fosstars.model.Subject;
+import com.sap.oss.phosphor.fosstars.model.Value;
+import com.sap.oss.phosphor.fosstars.model.score.oss.SnykDependencyScanScore;
+import com.sap.oss.phosphor.fosstars.model.value.ScoreValue;
+import java.net.MalformedURLException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * An advisor for features related to Snyk.
+ */
+public class SnykAdvisor extends AbstractOssAdvisor {
+
+ /**
+ * Create a new advisor.
+ *
+ * @param contextFactory A factory that provides contexts for advice.
+ */
+ public SnykAdvisor(OssAdviceContextFactory contextFactory) {
+ super(OssAdviceContentYamlStorage.DEFAULT, contextFactory);
+ }
+
+ @Override
+ protected List adviceFor(
+ Subject subject, List> usedValues, OssAdviceContext context)
+ throws MalformedURLException {
+
+ Optional snykScore = findSubScoreValue(subject, SnykDependencyScanScore.class);
+
+ if (!snykScore.isPresent() || snykScore.get().isNotApplicable()) {
+ return Collections.emptyList();
+ }
+
+ return adviceForBooleanFeature(usedValues, USES_SNYK, subject, context);
+ }
+}
diff --git a/src/main/java/com/sap/oss/phosphor/fosstars/data/DataProviderSelector.java b/src/main/java/com/sap/oss/phosphor/fosstars/data/DataProviderSelector.java
index cf9190a8d..956f1e586 100644
--- a/src/main/java/com/sap/oss/phosphor/fosstars/data/DataProviderSelector.java
+++ b/src/main/java/com/sap/oss/phosphor/fosstars/data/DataProviderSelector.java
@@ -56,6 +56,7 @@
import com.sap.oss.phosphor.fosstars.data.github.UsesOwaspDependencyCheck;
import com.sap.oss.phosphor.fosstars.data.github.UsesSanitizers;
import com.sap.oss.phosphor.fosstars.data.github.UsesSignedCommits;
+import com.sap.oss.phosphor.fosstars.data.github.UsesSnyk;
import com.sap.oss.phosphor.fosstars.data.github.VulnerabilityAlertsInfo;
import com.sap.oss.phosphor.fosstars.data.interactive.AskAboutSecurityTeam;
import com.sap.oss.phosphor.fosstars.data.interactive.AskAboutUnpatchedVulnerabilities;
@@ -210,6 +211,7 @@ public DataProviderSelector(GitHubDataFetcher fetcher, NVD nvd) throws IOExcepti
new LgtmDataProvider(fetcher),
new UsesSignedCommits(fetcher),
new UsesDependabot(fetcher),
+ new UsesSnyk(fetcher),
new ProgrammingLanguages(fetcher),
new PackageManagement(fetcher),
new UsesNoHttpTool(fetcher),
diff --git a/src/main/java/com/sap/oss/phosphor/fosstars/data/github/AbstractDependencyScanDataProvider.java b/src/main/java/com/sap/oss/phosphor/fosstars/data/github/AbstractDependencyScanDataProvider.java
new file mode 100644
index 000000000..19ec932e3
--- /dev/null
+++ b/src/main/java/com/sap/oss/phosphor/fosstars/data/github/AbstractDependencyScanDataProvider.java
@@ -0,0 +1,140 @@
+package com.sap.oss.phosphor.fosstars.data.github;
+
+import com.sap.oss.phosphor.fosstars.model.subject.oss.GitHubProject;
+import java.io.IOException;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Date;
+import java.util.Optional;
+import org.kohsuke.github.GHIssueState;
+import org.kohsuke.github.GHPullRequest;
+import org.kohsuke.github.GHUser;
+
+/**
+ * This is a base class for dependency checker data providers such as Dependabot and Snyk.
+ */
+public abstract class AbstractDependencyScanDataProvider extends GitHubCachingDataProvider {
+
+ /**
+ * Period of time to be checked.
+ */
+ private static final Duration ONE_YEAR = Duration.ofDays(365);
+
+ /**
+ * A minimal number of characters in a config for dependency checker.
+ */
+ private static final int ACCEPTABLE_CONFIG_SIZE = 10;
+
+ protected abstract String getDependencyCheckerPattern();
+
+ /**
+ * Initializes a data provider.
+ *
+ * @param fetcher An interface to GitHub.
+ */
+ public AbstractDependencyScanDataProvider(
+ GitHubDataFetcher fetcher) {
+ super(fetcher);
+ }
+
+ /**
+ * Checks if a repository contains commits from dependency checker in the commit history.
+ *
+ * @param repository The repository.
+ * @return True if at least one commit from dependency checker was found, false otherwise.
+ */
+ public boolean hasDependencyCheckerCommits(LocalRepository repository) {
+ Date date = Date.from(Instant.now().minus(ONE_YEAR));
+
+ try {
+ for (Commit commit : repository.commitsAfter(date)) {
+ if (isDependencyChecker(commit)) {
+ return true;
+ }
+ }
+ } catch (IOException e) {
+ logger.warn("Something went wrong!", e);
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks if a repository has a configuration file for dependency checker.
+ *
+ * @param repository The repository
+ * @param configs The config files path as String array
+ * @return True if a config was found, false otherwise.
+ * @throws IOException If something went wrong.
+ */
+ public boolean hasDependencyCheckerConfig(LocalRepository repository, String[] configs)
+ throws IOException {
+ for (String config : configs) {
+ Optional content = repository.file(config);
+ if (content.isPresent() && content.get().length() >= ACCEPTABLE_CONFIG_SIZE) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks whether a project has open pull requests from dependency checker.
+ *
+ * @param project The project.
+ * @return True if the project has open pull requests form dependency checker.
+ * @throws IOException If something went wrong.
+ */
+ public boolean hasOpenPullRequestFromDependencyChecker(GitHubProject project) throws IOException {
+ return fetcher.repositoryFor(project).getPullRequests(GHIssueState.OPEN).stream()
+ .anyMatch(this::createdByDependencyChecker);
+ }
+
+ /**
+ * Checks if a pull request was created by dependency checker.
+ *
+ * @param pullRequest The pull request.
+ * @return True if the user looks like dependency checker, false otherwise.
+ */
+ private boolean createdByDependencyChecker(GHPullRequest pullRequest) {
+ try {
+ GHUser user = pullRequest.getUser();
+ return isDependencyChecker(user.getName()) || isDependencyChecker(user.getLogin());
+ } catch (IOException e) {
+ logger.warn("Oops! Could not fetch name or login!", e);
+ return false;
+ }
+ }
+
+ /**
+ * Checks if a commit was done by dependency checker.
+ *
+ * @param commit The commit to be checked.
+ * @return True if the commit was done by dependency checker, false otherwise.
+ */
+ private boolean isDependencyChecker(Commit commit) {
+ if (isDependencyChecker(commit.authorName()) || isDependencyChecker(commit.committerName())) {
+ return true;
+ }
+
+ for (String line : commit.message()) {
+ if ((line.startsWith("Signed-off-by:") || line.startsWith("Co-authored-by:"))
+ && line.contains(getDependencyCheckerPattern())) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks whether a name looks like dependency checker.
+ *
+ * @param name The name.
+ * @return True if the name looks like dependency checker, false otherwise.
+ */
+ private boolean isDependencyChecker(String name) {
+ return name != null && name.toLowerCase().contains(getDependencyCheckerPattern());
+ }
+}
diff --git a/src/main/java/com/sap/oss/phosphor/fosstars/data/github/HasExecutableBinaries.java b/src/main/java/com/sap/oss/phosphor/fosstars/data/github/HasExecutableBinaries.java
index 74861e003..ddc61abaf 100644
--- a/src/main/java/com/sap/oss/phosphor/fosstars/data/github/HasExecutableBinaries.java
+++ b/src/main/java/com/sap/oss/phosphor/fosstars/data/github/HasExecutableBinaries.java
@@ -10,8 +10,6 @@
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
-import org.kohsuke.github.GitHub;
-import org.kohsuke.github.GitHubBuilder;
/**
* The data provider tries to figure out if an open-source project has executable binaries (for
diff --git a/src/main/java/com/sap/oss/phosphor/fosstars/data/github/PackageManagement.java b/src/main/java/com/sap/oss/phosphor/fosstars/data/github/PackageManagement.java
index 9a5b370e2..bd18147f7 100644
--- a/src/main/java/com/sap/oss/phosphor/fosstars/data/github/PackageManagement.java
+++ b/src/main/java/com/sap/oss/phosphor/fosstars/data/github/PackageManagement.java
@@ -4,6 +4,7 @@
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.PACKAGE_MANAGERS;
import static com.sap.oss.phosphor.fosstars.model.value.Language.C_SHARP;
import static com.sap.oss.phosphor.fosstars.model.value.Language.F_SHARP;
+import static com.sap.oss.phosphor.fosstars.model.value.Language.GO;
import static com.sap.oss.phosphor.fosstars.model.value.Language.JAVA;
import static com.sap.oss.phosphor.fosstars.model.value.Language.JAVASCRIPT;
import static com.sap.oss.phosphor.fosstars.model.value.Language.PHP;
@@ -13,6 +14,7 @@
import static com.sap.oss.phosphor.fosstars.model.value.Language.VISUALBASIC;
import static com.sap.oss.phosphor.fosstars.model.value.PackageManager.COMPOSER;
import static com.sap.oss.phosphor.fosstars.model.value.PackageManager.DOTNET;
+import static com.sap.oss.phosphor.fosstars.model.value.PackageManager.GOMODULES;
import static com.sap.oss.phosphor.fosstars.model.value.PackageManager.GRADLE;
import static com.sap.oss.phosphor.fosstars.model.value.PackageManager.MAVEN;
import static com.sap.oss.phosphor.fosstars.model.value.PackageManager.NPM;
@@ -63,6 +65,7 @@ public class PackageManagement extends CachedSingleFeatureGitHubDataProviderThis data provider checks if an open-source project on GitHub
@@ -28,7 +21,7 @@
* Next, the provider searches for commits from Dependabot in the commit history.
* If the commits are found, then the provider also reports that the project uses Dependabot.
*/
-public class UsesDependabot extends GitHubCachingDataProvider {
+public class UsesDependabot extends AbstractDependencyScanDataProvider {
/**
* A list of locations of a Dependabot configuration file in a repository.
@@ -41,20 +34,15 @@ public class UsesDependabot extends GitHubCachingDataProvider {
".github/dependabot.yml"
};
- /**
- * A minimal number of characters in a config for Dependabot.
- */
- private static final int ACCEPTABLE_CONFIG_SIZE = 10;
-
/**
* A pattern to detect commits by Dependabot.
*/
private static final String DEPENDABOT_PATTERN = "dependabot";
- /**
- * Period of time to be checked.
- */
- private static final Duration ONE_YEAR = Duration.ofDays(365);
+ @Override
+ protected String getDependencyCheckerPattern() {
+ return DEPENDABOT_PATTERN;
+ }
/**
* Initializes a data provider.
@@ -77,105 +65,10 @@ protected ValueSet fetchValuesFor(GitHubProject project) throws IOException {
LocalRepository repository = GitHubDataFetcher.localRepositoryFor(project);
return ValueHashSet.from(
- USES_DEPENDABOT.value(hasDependabotConfig(repository) || hasDependabotCommits(repository)),
- HAS_OPEN_PULL_REQUEST_FROM_DEPENDABOT.value(hasOpenPullRequestFromDependabot(project)));
- }
-
- /**
- * Checks if a repository contains commits from Dependabot in the commit history.
- *
- * @param repository The repository.
- * @return True if at least one commit from Dependabot was found, false otherwise.
- */
- private boolean hasDependabotCommits(LocalRepository repository) {
- Date date = Date.from(Instant.now().minus(ONE_YEAR));
-
- try {
- for (Commit commit : repository.commitsAfter(date)) {
- if (isDependabot(commit)) {
- return true;
- }
- }
- } catch (IOException e) {
- logger.warn("Something went wrong!", e);
- }
-
- return false;
- }
-
- /**
- * Checks if a repository has a configuration file for Dependabot.
- *
- * @param repository The repository
- * @return True if a config was found, false otherwise.
- */
- private boolean hasDependabotConfig(LocalRepository repository) throws IOException {
- for (String config : DEPENDABOT_CONFIGS) {
- Optional content = repository.file(config);
- if (content.isPresent() && content.get().length() >= ACCEPTABLE_CONFIG_SIZE) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Checks whether a project has open pull requests from Dependabot.
- *
- * @param project The project.
- * @return True if the project has open pull requests form Dependabot.
- * @throws IOException If something went wrong.
- */
- private boolean hasOpenPullRequestFromDependabot(GitHubProject project) throws IOException {
- return fetcher.repositoryFor(project).getPullRequests(GHIssueState.OPEN).stream()
- .anyMatch(this::createdByDependabot);
- }
-
- /**
- * Checks if a pull request was created by Dependabot.
- *
- * @param pullRequest The pull request.
- * @return True if the user looks like Dependabot, false otherwise.
- */
- private boolean createdByDependabot(GHPullRequest pullRequest) {
- try {
- GHUser user = pullRequest.getUser();
- return isDependabot(user.getName()) || isDependabot(user.getLogin());
- } catch (IOException e) {
- logger.warn("Oops! Could not fetch name or login!", e);
- return false;
- }
- }
-
- /**
- * Checks if a commit was done by Dependabot.
- *
- * @param commit The commit to be checked.
- * @return True if the commit was done by Dependabot, false otherwise.
- */
- private static boolean isDependabot(Commit commit) {
- if (isDependabot(commit.authorName()) || isDependabot(commit.committerName())) {
- return true;
- }
-
- for (String line : commit.message()) {
- if ((line.startsWith("Signed-off-by:") || line.startsWith("Co-authored-by:"))
- && line.contains(DEPENDABOT_PATTERN)) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Checks whether a name looks like Dependabot.
- *
- * @param name The name.
- * @return True if the name looks like Dependabot, false otherwise.
- */
- private static boolean isDependabot(String name) {
- return name != null && name.toLowerCase().contains(DEPENDABOT_PATTERN);
+ USES_DEPENDABOT.value(
+ hasDependencyCheckerConfig(repository, DEPENDABOT_CONFIGS)
+ || hasDependencyCheckerCommits(repository)),
+ HAS_OPEN_PULL_REQUEST_FROM_DEPENDABOT.value(
+ hasOpenPullRequestFromDependencyChecker(project)));
}
}
\ No newline at end of file
diff --git a/src/main/java/com/sap/oss/phosphor/fosstars/data/github/UsesSnyk.java b/src/main/java/com/sap/oss/phosphor/fosstars/data/github/UsesSnyk.java
new file mode 100644
index 000000000..98f8fb85d
--- /dev/null
+++ b/src/main/java/com/sap/oss/phosphor/fosstars/data/github/UsesSnyk.java
@@ -0,0 +1,106 @@
+package com.sap.oss.phosphor.fosstars.data.github;
+
+import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.HAS_OPEN_PULL_REQUEST_FROM_SNYK;
+import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_SNYK;
+import static com.sap.oss.phosphor.fosstars.model.other.Utils.setOf;
+
+import com.sap.oss.phosphor.fosstars.model.Feature;
+import com.sap.oss.phosphor.fosstars.model.ValueSet;
+import com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures;
+import com.sap.oss.phosphor.fosstars.model.subject.oss.GitHubProject;
+import com.sap.oss.phosphor.fosstars.model.value.ValueHashSet;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Predicate;
+
+/**
+ * This data provider checks if an open-source project on GitHub uses Snyk, and fills out the {@link
+ * OssFeatures#USES_SNYK} feature.
+ *
+ * First, the provider checks if a repository contains a policy file for Snyk. If the policy file
+ * exists, then the provider reports that the project uses Snyk. Next, the provider searches for
+ * commits from Snyk in the commit history. If the commits are found, then the provider also reports
+ * that the project uses Snyk.
+ */
+public class UsesSnyk extends AbstractDependencyScanDataProvider {
+
+ /**
+ * A file name containing Snyk policies in a repository.
+ *
+ * @see The .snyk
+ * file
+ */
+ private static String SNYK_POLICY_FILE_NAME = ".snyk";
+
+ /**
+ * A location of a Snyk configuration file in a repository.
+ *
+ * @see To setup Snyk actions
+ *
+ */
+ private static final String [] SNYK_CONFIGS = {
+ ".github/workflows/snyk.yaml",
+ ".github/workflows/snyk.yml"
+ };
+
+ /**
+ * Predicate to confirm if there is a file in open-source project with the .snyk extension.
+ */
+ private static final Predicate SNYK_FILE_PREDICATE =
+ path -> path.getFileName().toString().endsWith(SNYK_POLICY_FILE_NAME);
+
+ /**
+ * A pattern to detect commits by Snyk.
+ *
+ * @see Snyk
+ * commit signing
+ */
+ private static final String SNYK_PATTERN = "snyk";
+
+ @Override
+ protected String getDependencyCheckerPattern() {
+ return SNYK_PATTERN;
+ }
+
+ /**
+ * Initializes a data provider.
+ *
+ * @param fetcher An interface to GitHub.
+ */
+ public UsesSnyk(GitHubDataFetcher fetcher) {
+ super(fetcher);
+ }
+
+ @Override
+ public Set> supportedFeatures() {
+ return setOf(USES_SNYK, HAS_OPEN_PULL_REQUEST_FROM_SNYK);
+ }
+
+ @Override
+ protected ValueSet fetchValuesFor(GitHubProject project) throws IOException {
+ logger.info("Checking how the project uses Snyk ...");
+
+ LocalRepository repository = GitHubDataFetcher.localRepositoryFor(project);
+
+ return ValueHashSet.from(
+ USES_SNYK.value(
+ hasSnykPolicy(repository)
+ || hasDependencyCheckerConfig(repository, SNYK_CONFIGS)
+ || hasDependencyCheckerCommits(repository)),
+ HAS_OPEN_PULL_REQUEST_FROM_SNYK.value(hasOpenPullRequestFromDependencyChecker(project)));
+ }
+
+ /**
+ * Checks if a repository has a policy file for Snyk.
+ *
+ * @param repository The repository
+ * @return True if a policy file was found, false otherwise.
+ */
+ private boolean hasSnykPolicy(LocalRepository repository) throws IOException {
+ List snykPolicyFilePaths = repository.files(SNYK_FILE_PREDICATE);
+ return !snykPolicyFilePaths.isEmpty();
+ }
+}
diff --git a/src/main/java/com/sap/oss/phosphor/fosstars/model/Score.java b/src/main/java/com/sap/oss/phosphor/fosstars/model/Score.java
index 760b54b43..354eeefed 100644
--- a/src/main/java/com/sap/oss/phosphor/fosstars/model/Score.java
+++ b/src/main/java/com/sap/oss/phosphor/fosstars/model/Score.java
@@ -137,4 +137,14 @@ static double adjust(double value) {
return value;
}
+ /**
+ * Get an Interval with the provided range.
+ *
+ * @param min An interval start value.
+ * @param max An interval end value.
+ * @return Interval with the range provided from min and max param values.
+ */
+ static Interval makeInterval(double min, double max) {
+ return DoubleInterval.init().from(min).to(max).closed().make();
+ }
}
diff --git a/src/main/java/com/sap/oss/phosphor/fosstars/model/feature/oss/OssFeatures.java b/src/main/java/com/sap/oss/phosphor/fosstars/model/feature/oss/OssFeatures.java
index c9da290fc..b3884d6af 100755
--- a/src/main/java/com/sap/oss/phosphor/fosstars/model/feature/oss/OssFeatures.java
+++ b/src/main/java/com/sap/oss/phosphor/fosstars/model/feature/oss/OssFeatures.java
@@ -171,6 +171,29 @@ private OssFeatures() {
public static final BooleanFeature HAS_OPEN_PULL_REQUEST_FROM_DEPENDABOT
= new BooleanFeature("If a project has open pull requests from Dependabot");
+ /**
+ * Shows if a project uses Snyk.
+ * Snyk introduction offers
+ *
+ * - Static Application Security Testing (SAST)
+ * - Automatic dependency updates
+ *
+ * In particular for automatic dependency updates,
+ * when Snyk finds a vulnerability in dependencies,
+ * it opens a pull request to update the vulnerable dependency to the safe version.
+ */
+ public static final Feature USES_SNYK
+ = new BooleanFeature("If a project uses Snyk");
+
+ /**
+ * Shows if an open source project has open pull requests from Snyk which means that
+ * there are dependencies with known vulnerabilities.
+ *
+ * @see Snyk
+ */
+ public static final BooleanFeature HAS_OPEN_PULL_REQUEST_FROM_SNYK
+ = new BooleanFeature("If a project has open pull requests from Snyk");
+
/**
* Shows how many GitHub users starred an open-source project.
*/
diff --git a/src/main/java/com/sap/oss/phosphor/fosstars/model/score/oss/DependabotScore.java b/src/main/java/com/sap/oss/phosphor/fosstars/model/score/oss/DependabotScore.java
index 49d835fb4..9d9a46691 100644
--- a/src/main/java/com/sap/oss/phosphor/fosstars/model/score/oss/DependabotScore.java
+++ b/src/main/java/com/sap/oss/phosphor/fosstars/model/score/oss/DependabotScore.java
@@ -70,7 +70,7 @@ public class DependabotScore extends FeatureBasedScore {
* A score value that is returned if it's likely
* that a project uses the security alerts on GitHub.
*/
- private static final double GITHUB_ALERTS_SCORE_VALUE = 6.0;
+ private static final double GITHUB_ALERTS_SCORE_VALUE = 5.0;
/**
* Initializes a new score.
diff --git a/src/main/java/com/sap/oss/phosphor/fosstars/model/score/oss/DependencyScanScore.java b/src/main/java/com/sap/oss/phosphor/fosstars/model/score/oss/DependencyScanScore.java
index 77454fdc8..9e23ffd29 100644
--- a/src/main/java/com/sap/oss/phosphor/fosstars/model/score/oss/DependencyScanScore.java
+++ b/src/main/java/com/sap/oss/phosphor/fosstars/model/score/oss/DependencyScanScore.java
@@ -18,6 +18,7 @@
*
* - {@link DependabotScore}
* - {@link OwaspDependencyScanScore}
+ * - {@link SnykDependencyScanScore}
*
*/
public class DependencyScanScore extends AbstractScore {
@@ -32,11 +33,17 @@ public class DependencyScanScore extends AbstractScore {
*/
private final OwaspDependencyScanScore owaspDependencyCheckScore;
+ /**
+ * A score that shows how a project uses Snyk.
+ */
+ private final SnykDependencyScanScore snykDependencyScanScore;
+
/**
* Initializes a new score.
*/
public DependencyScanScore() {
super("How a project scans its dependencies for vulnerabilities");
+ this.snykDependencyScanScore = new SnykDependencyScanScore();
this.dependabotScore = new DependabotScore();
this.owaspDependencyCheckScore = new OwaspDependencyScanScore();
}
@@ -48,30 +55,36 @@ public Set> features() {
@Override
public Set subScores() {
- return setOf(dependabotScore, owaspDependencyCheckScore);
+ return setOf(dependabotScore, snykDependencyScanScore, owaspDependencyCheckScore);
}
@Override
public ScoreValue calculate(Value>... values) {
Objects.requireNonNull(values, "Oh no! Values is null!");
+ ScoreValue snykDependencyScanScoreValue = calculateIfNecessary(snykDependencyScanScore, values);
ScoreValue dependabotScoreValue = calculateIfNecessary(dependabotScore, values);
ScoreValue owaspDependencyCheckScoreValue
= calculateIfNecessary(owaspDependencyCheckScore, values);
- ScoreValue scoreValue = scoreValue(MIN, dependabotScoreValue, owaspDependencyCheckScoreValue);
+ ScoreValue scoreValue = scoreValue(MIN, dependabotScoreValue,
+ snykDependencyScanScoreValue, owaspDependencyCheckScoreValue);
- if (allUnknown(dependabotScoreValue, owaspDependencyCheckScoreValue)) {
+ if (allUnknown(dependabotScoreValue, snykDependencyScanScoreValue,
+ owaspDependencyCheckScoreValue)) {
return scoreValue.makeUnknown();
}
- if (allNotApplicable(dependabotScoreValue, owaspDependencyCheckScoreValue)) {
+ if (allNotApplicable(dependabotScoreValue, snykDependencyScanScoreValue,
+ owaspDependencyCheckScoreValue)) {
return scoreValue.makeNotApplicable();
}
+ scoreValue.increase(snykDependencyScanScoreValue.orElse(MIN));
scoreValue.increase(dependabotScoreValue.orElse(MIN));
scoreValue.increase(owaspDependencyCheckScoreValue.orElse(MIN));
- scoreValue.confidence(Confidence.make(dependabotScoreValue, owaspDependencyCheckScoreValue));
+ scoreValue.confidence(Confidence.make(dependabotScoreValue, snykDependencyScanScoreValue,
+ owaspDependencyCheckScoreValue));
return scoreValue;
}
diff --git a/src/main/java/com/sap/oss/phosphor/fosstars/model/score/oss/ProjectSecurityAwarenessScore.java b/src/main/java/com/sap/oss/phosphor/fosstars/model/score/oss/ProjectSecurityAwarenessScore.java
index 8830a1c09..e6e16ebd3 100644
--- a/src/main/java/com/sap/oss/phosphor/fosstars/model/score/oss/ProjectSecurityAwarenessScore.java
+++ b/src/main/java/com/sap/oss/phosphor/fosstars/model/score/oss/ProjectSecurityAwarenessScore.java
@@ -17,6 +17,7 @@
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_OWASP_JAVA_ENCODER;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_OWASP_JAVA_HTML_SANITIZER;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_SIGNED_COMMITS;
+import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_SNYK;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_UNDEFINED_BEHAVIOR_SANITIZER;
import static com.sap.oss.phosphor.fosstars.model.value.OwaspDependencyCheckUsage.NOT_USED;
@@ -62,6 +63,9 @@
* {@link com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures#USES_DEPENDABOT}
*
*
+ * {@link com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures#USES_SNYK}
+ *
+ *
* {@link com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures#USES_NOHTTP}
*
*
@@ -157,7 +161,7 @@ public class ProjectSecurityAwarenessScore extends FeatureBasedScore {
*/
private static final Feature>[] SECURITY_TOOLS_FEATURES = new Feature[] {
FUZZED_IN_OSS_FUZZ,
- USES_DEPENDABOT,
+ USES_DEPENDABOT, USES_SNYK,
USES_NOHTTP, USES_LGTM_CHECKS, USES_FIND_SEC_BUGS,
USES_OWASP_ESAPI, USES_OWASP_JAVA_ENCODER, USES_OWASP_JAVA_HTML_SANITIZER,
USES_ADDRESS_SANITIZER, USES_MEMORY_SANITIZER, USES_UNDEFINED_BEHAVIOR_SANITIZER,
diff --git a/src/main/java/com/sap/oss/phosphor/fosstars/model/score/oss/SnykDependencyScanScore.java b/src/main/java/com/sap/oss/phosphor/fosstars/model/score/oss/SnykDependencyScanScore.java
new file mode 100644
index 000000000..aad055652
--- /dev/null
+++ b/src/main/java/com/sap/oss/phosphor/fosstars/model/score/oss/SnykDependencyScanScore.java
@@ -0,0 +1,114 @@
+package com.sap.oss.phosphor.fosstars.model.score.oss;
+
+import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.LANGUAGES;
+import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.PACKAGE_MANAGERS;
+import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_GITHUB_FOR_DEVELOPMENT;
+import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_SNYK;
+import static com.sap.oss.phosphor.fosstars.model.value.Language.CPP;
+import static com.sap.oss.phosphor.fosstars.model.value.Language.C_SHARP;
+import static com.sap.oss.phosphor.fosstars.model.value.Language.F_SHARP;
+import static com.sap.oss.phosphor.fosstars.model.value.Language.GO;
+import static com.sap.oss.phosphor.fosstars.model.value.Language.JAVA;
+import static com.sap.oss.phosphor.fosstars.model.value.Language.JAVASCRIPT;
+import static com.sap.oss.phosphor.fosstars.model.value.Language.PHP;
+import static com.sap.oss.phosphor.fosstars.model.value.Language.PYTHON;
+import static com.sap.oss.phosphor.fosstars.model.value.Language.RUBY;
+import static com.sap.oss.phosphor.fosstars.model.value.Language.SCALA;
+import static com.sap.oss.phosphor.fosstars.model.value.Language.VISUALBASIC;
+import static com.sap.oss.phosphor.fosstars.model.value.PackageManager.COMPOSER;
+import static com.sap.oss.phosphor.fosstars.model.value.PackageManager.DOTNET;
+import static com.sap.oss.phosphor.fosstars.model.value.PackageManager.GOMODULES;
+import static com.sap.oss.phosphor.fosstars.model.value.PackageManager.MAVEN;
+import static com.sap.oss.phosphor.fosstars.model.value.PackageManager.NPM;
+import static com.sap.oss.phosphor.fosstars.model.value.PackageManager.PIP;
+import static com.sap.oss.phosphor.fosstars.model.value.PackageManager.RUBYGEMS;
+import static com.sap.oss.phosphor.fosstars.model.value.PackageManager.YARN;
+
+import com.sap.oss.phosphor.fosstars.model.Score;
+import com.sap.oss.phosphor.fosstars.model.Value;
+import com.sap.oss.phosphor.fosstars.model.score.FeatureBasedScore;
+import com.sap.oss.phosphor.fosstars.model.value.Languages;
+import com.sap.oss.phosphor.fosstars.model.value.PackageManager;
+import com.sap.oss.phosphor.fosstars.model.value.PackageManagers;
+import com.sap.oss.phosphor.fosstars.model.value.ScoreValue;
+import java.util.HashMap;
+import java.util.Map;
+
+public class SnykDependencyScanScore extends FeatureBasedScore {
+
+ private static final Map SUPPORTED_LANGUAGES = new HashMap<>();
+
+ static {
+ SUPPORTED_LANGUAGES.put(MAVEN, Languages.of(JAVA, SCALA));
+ SUPPORTED_LANGUAGES.put(NPM, Languages.of(JAVASCRIPT));
+ SUPPORTED_LANGUAGES.put(YARN, Languages.of(JAVASCRIPT));
+ SUPPORTED_LANGUAGES.put(DOTNET, Languages.of(C_SHARP, F_SHARP, CPP, VISUALBASIC));
+ SUPPORTED_LANGUAGES.put(PIP, Languages.of(PYTHON));
+ SUPPORTED_LANGUAGES.put(RUBYGEMS, Languages.of(RUBY));
+ SUPPORTED_LANGUAGES.put(COMPOSER, Languages.of(PHP));
+ SUPPORTED_LANGUAGES.put(GOMODULES, Languages.of(GO));
+ }
+
+ /**
+ * A score value that is returned if it's likely that a project uses the security alerts on
+ * GitHub.
+ */
+ private static final double GITHUB_ALERTS_SCORE_VALUE = 5.0;
+
+ /** Initializes a new score. */
+ public SnykDependencyScanScore() {
+ super(
+ "How a project uses Snyk",
+ USES_SNYK,
+ USES_GITHUB_FOR_DEVELOPMENT,
+ PACKAGE_MANAGERS,
+ LANGUAGES);
+ }
+
+ @Override
+ public ScoreValue calculate(Value>... values) {
+ Value usesSnyk = find(USES_SNYK, values);
+ Value usesGithub = find(USES_GITHUB_FOR_DEVELOPMENT, values);
+ Value languages = find(LANGUAGES, values);
+ Value packageManagers = find(PACKAGE_MANAGERS, values);
+
+ ScoreValue scoreValue = scoreValue(Score.MIN, usesSnyk, usesGithub, packageManagers, languages);
+
+ if (allUnknown(scoreValue.usedValues())) {
+ return scoreValue.makeUnknown();
+ }
+
+ // if the project uses Snyk,
+ // then we're happy
+ if (usesSnyk.orElse(false)) {
+ return scoreValue.set(Score.MAX);
+ }
+
+ // if the projects uses GitHub for development,
+ // then there is a chance that it takes advantage of security alerts,
+ // although we can't tell for sure
+ if (usesGithub.orElse(false)) {
+ boolean snykCanBeUsed =
+ packageManagers.orElse(PackageManagers.empty()).list().stream()
+ .anyMatch(SUPPORTED_LANGUAGES::containsKey);
+
+ // if the project does not use any package ecosystem that is supported by Snyk,
+ // then a score is not applicable
+ if (!snykCanBeUsed) {
+ return scoreValue.makeNotApplicable();
+ }
+
+ Languages usedLanguages = languages.orElse(Languages.empty());
+ for (PackageManager packageManager : packageManagers.orElse(PackageManagers.empty())) {
+ Languages supportedLanguages =
+ SUPPORTED_LANGUAGES.getOrDefault(packageManager, Languages.empty());
+ if (supportedLanguages.containsAnyOf(usedLanguages)) {
+ return scoreValue.set(GITHUB_ALERTS_SCORE_VALUE);
+ }
+ }
+ }
+
+ // otherwise, return the minimal score
+ return scoreValue.set(Score.MIN);
+ }
+}
diff --git a/src/main/java/com/sap/oss/phosphor/fosstars/model/value/PackageManager.java b/src/main/java/com/sap/oss/phosphor/fosstars/model/value/PackageManager.java
index 4b84c12df..4a6d05826 100644
--- a/src/main/java/com/sap/oss/phosphor/fosstars/model/value/PackageManager.java
+++ b/src/main/java/com/sap/oss/phosphor/fosstars/model/value/PackageManager.java
@@ -7,7 +7,7 @@ public enum PackageManager {
MAVEN, GRADLE,
- NPM, YARN, DOTNET, PIP, RUBYGEMS, COMPOSER,
+ NPM, YARN, DOTNET, PIP, RUBYGEMS, COMPOSER, GOMODULES,
OTHER
}
diff --git a/src/main/java/com/sap/oss/phosphor/fosstars/tool/format/CommonFormatter.java b/src/main/java/com/sap/oss/phosphor/fosstars/tool/format/CommonFormatter.java
index a70eb625b..6f03d459f 100755
--- a/src/main/java/com/sap/oss/phosphor/fosstars/tool/format/CommonFormatter.java
+++ b/src/main/java/com/sap/oss/phosphor/fosstars/tool/format/CommonFormatter.java
@@ -13,6 +13,7 @@
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.HAS_EXECUTABLE_BINARIES;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.HAS_LICENSE;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.HAS_OPEN_PULL_REQUEST_FROM_DEPENDABOT;
+import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.HAS_OPEN_PULL_REQUEST_FROM_SNYK;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.HAS_README;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.HAS_REQUIRED_TEXT_IN_CODE_OF_CONDUCT_GUIDELINE;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.HAS_REQUIRED_TEXT_IN_CONTRIBUTING_GUIDELINE;
@@ -50,6 +51,7 @@
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_OWASP_JAVA_HTML_SANITIZER;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_REUSE;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_SIGNED_COMMITS;
+import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_SNYK;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_UNDEFINED_BEHAVIOR_SANITIZER;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.VULNERABILITIES_IN_ARTIFACT;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.VULNERABILITIES_IN_PROJECT;
@@ -82,6 +84,7 @@
import com.sap.oss.phosphor.fosstars.model.score.oss.ProjectSecurityAwarenessScore;
import com.sap.oss.phosphor.fosstars.model.score.oss.ProjectSecurityTestingScore;
import com.sap.oss.phosphor.fosstars.model.score.oss.SecurityReviewScore;
+import com.sap.oss.phosphor.fosstars.model.score.oss.SnykDependencyScanScore;
import com.sap.oss.phosphor.fosstars.model.score.oss.StaticAnalysisScore;
import com.sap.oss.phosphor.fosstars.model.score.oss.UnpatchedVulnerabilitiesScore;
import com.sap.oss.phosphor.fosstars.model.score.oss.VulnerabilityDiscoveryAndSecurityTestingScore;
@@ -123,6 +126,7 @@ public abstract class CommonFormatter implements Formatter {
add(VulnerabilityLifetimeScore.class, "Vulnerability lifetime");
add(MemorySafetyTestingScore.class, "Memory-safety testing");
add(DependabotScore.class, "Dependabot score");
+ add(SnykDependencyScanScore.class, "Snyk score");
add(OwaspDependencyScanScore.class, "OWASP Dependency Check score");
add(DependencyScanScore.class, "Dependency testing");
add(FuzzingScore.class, "Fuzzing");
@@ -175,6 +179,7 @@ private static void add(Class extends Feature>> clazz, String caption) {
add(USES_OWASP_JAVA_ENCODER, "Does it use OWASP Java Encoder?");
add(USES_OWASP_JAVA_HTML_SANITIZER, "Does it use OWASP Java HTML Sanitizer?");
add(USES_DEPENDABOT, "Does it use Dependabot?");
+ add(USES_SNYK, "Does it use Snyk?");
add(USES_LGTM_CHECKS, "Does it use LGTM checks?");
add(HAS_BUG_BOUNTY_PROGRAM, "Does it have a bug bounty program?");
add(SIGNS_ARTIFACTS, "Does it sign artifacts?");
@@ -190,6 +195,8 @@ private static void add(Class extends Feature>> clazz, String caption) {
add(IS_REUSE_COMPLIANT, "Is it compliant with REUSE rules?");
add(HAS_OPEN_PULL_REQUEST_FROM_DEPENDABOT,
"Does the project have open pull requests from Dependabot?");
+ add(HAS_OPEN_PULL_REQUEST_FROM_SNYK,
+ "Does the project have open pull requests from Snyk?");
add(PACKAGE_MANAGERS, "Package managers");
add(LANGUAGES, "Programming languages");
add(RUNS_CODEQL_SCANS, "Does it run CodeQL scans?");
diff --git a/src/main/java/com/sap/oss/phosphor/fosstars/util/Deserialization.java b/src/main/java/com/sap/oss/phosphor/fosstars/util/Deserialization.java
index 1ee7a8d82..a1cca5760 100644
--- a/src/main/java/com/sap/oss/phosphor/fosstars/util/Deserialization.java
+++ b/src/main/java/com/sap/oss/phosphor/fosstars/util/Deserialization.java
@@ -68,6 +68,7 @@
import com.sap.oss.phosphor.fosstars.model.score.oss.ProjectSecurityAwarenessScore;
import com.sap.oss.phosphor.fosstars.model.score.oss.ProjectSecurityTestingScore;
import com.sap.oss.phosphor.fosstars.model.score.oss.SecurityReviewScore;
+import com.sap.oss.phosphor.fosstars.model.score.oss.SnykDependencyScanScore;
import com.sap.oss.phosphor.fosstars.model.score.oss.StaticAnalysisScore;
import com.sap.oss.phosphor.fosstars.model.score.oss.UnpatchedVulnerabilitiesScore;
import com.sap.oss.phosphor.fosstars.model.score.oss.VulnerabilityDiscoveryAndSecurityTestingScore;
@@ -289,6 +290,7 @@ static ObjectMapper registerSubTypesIn(ObjectMapper mapper) {
FuzzingScore.class,
StaticAnalysisScore.class,
DependabotScore.class,
+ SnykDependencyScanScore.class,
OwaspDependencyScanScore.class,
VulnerabilityDiscoveryAndSecurityTestingScore.class,
SecurityReviewScore.class,
diff --git a/src/main/resources/com/sap/oss/phosphor/fosstars/advice/oss/OssAdvice.yml b/src/main/resources/com/sap/oss/phosphor/fosstars/advice/oss/OssAdvice.yml
index 5ebaca9d7..c5ad552c2 100644
--- a/src/main/resources/com/sap/oss/phosphor/fosstars/advice/oss/OssAdvice.yml
+++ b/src/main/resources/com/sap/oss/phosphor/fosstars/advice/oss/OssAdvice.yml
@@ -89,6 +89,12 @@ If a project uses Dependabot:
links:
- name: Configuration options for dependency updates
url: https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates
+If a project uses Snyk:
+ - advice: >
+ You can create Snyk account and configure your project.
+ links:
+ - name: Getting started with snyk for open source
+ url: https://docs.snyk.io/products/snyk-open-source/getting-started-snyk-open-source
How OWASP Dependency Check is used:
- advice: >
You can add OWASP Dependency Check to the project's build pipeline.
diff --git a/src/test/java/com/sap/oss/phosphor/fosstars/TestUtils.java b/src/test/java/com/sap/oss/phosphor/fosstars/TestUtils.java
index 72a5c192e..018c927e4 100644
--- a/src/test/java/com/sap/oss/phosphor/fosstars/TestUtils.java
+++ b/src/test/java/com/sap/oss/phosphor/fosstars/TestUtils.java
@@ -37,6 +37,7 @@
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_OWASP_JAVA_ENCODER;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_OWASP_JAVA_HTML_SANITIZER;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_SIGNED_COMMITS;
+import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_SNYK;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_UNDEFINED_BEHAVIOR_SANITIZER;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.VULNERABILITIES_IN_ARTIFACT;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.VULNERABILITIES_IN_PROJECT;
@@ -200,6 +201,7 @@ public static Set> getDefaultValues() {
WORST_LGTM_GRADE.value(LgtmGrade.B),
USES_NOHTTP.value(true),
USES_DEPENDABOT.value(true),
+ USES_SNYK.value(false),
USES_GITHUB_FOR_DEVELOPMENT.value(true),
LANGUAGES.value(Languages.of(JAVA)),
USES_ADDRESS_SANITIZER.value(false),
@@ -275,6 +277,7 @@ public static Set> getBestValues() {
WORST_LGTM_GRADE.value(LgtmGrade.A_PLUS),
USES_NOHTTP.value(true),
USES_DEPENDABOT.value(true),
+ USES_SNYK.value(true),
USES_GITHUB_FOR_DEVELOPMENT.value(true),
LANGUAGES.value(Languages.of(JAVA)),
USES_ADDRESS_SANITIZER.value(true),
diff --git a/src/test/java/com/sap/oss/phosphor/fosstars/advice/oss/BanditAdvisorTest.java b/src/test/java/com/sap/oss/phosphor/fosstars/advice/oss/BanditAdvisorTest.java
index 3b9d4b7e2..8f606ea02 100644
--- a/src/test/java/com/sap/oss/phosphor/fosstars/advice/oss/BanditAdvisorTest.java
+++ b/src/test/java/com/sap/oss/phosphor/fosstars/advice/oss/BanditAdvisorTest.java
@@ -2,10 +2,7 @@
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.LANGUAGES;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.RUNS_BANDIT_SCANS;
-import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.RUNS_CODEQL_SCANS;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_BANDIT_SCAN_CHECKS;
-import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_CODEQL_CHECKS;
-import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_LGTM_CHECKS;
import static com.sap.oss.phosphor.fosstars.model.other.Utils.allUnknown;
import static com.sap.oss.phosphor.fosstars.model.value.Language.PYTHON;
import static org.junit.Assert.assertEquals;
diff --git a/src/test/java/com/sap/oss/phosphor/fosstars/advice/oss/SnykAdvisorTest.java b/src/test/java/com/sap/oss/phosphor/fosstars/advice/oss/SnykAdvisorTest.java
new file mode 100644
index 000000000..0c7207d2e
--- /dev/null
+++ b/src/test/java/com/sap/oss/phosphor/fosstars/advice/oss/SnykAdvisorTest.java
@@ -0,0 +1,73 @@
+package com.sap.oss.phosphor.fosstars.advice.oss;
+
+import static com.sap.oss.phosphor.fosstars.advice.oss.AbstractOssAdvisor.OssAdviceContextFactory.WITH_EMPTY_CONTEXT;
+import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.LANGUAGES;
+import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.PACKAGE_MANAGERS;
+import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_GITHUB_FOR_DEVELOPMENT;
+import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_SNYK;
+import static com.sap.oss.phosphor.fosstars.model.other.Utils.allUnknown;
+import static com.sap.oss.phosphor.fosstars.model.value.Language.C;
+import static com.sap.oss.phosphor.fosstars.model.value.Language.GO;
+import static com.sap.oss.phosphor.fosstars.model.value.PackageManager.GOMODULES;
+import static com.sap.oss.phosphor.fosstars.model.value.PackageManager.OTHER;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.sap.oss.phosphor.fosstars.model.Rating;
+import com.sap.oss.phosphor.fosstars.model.RatingRepository;
+import com.sap.oss.phosphor.fosstars.model.ValueSet;
+import com.sap.oss.phosphor.fosstars.model.rating.oss.OssSecurityRating;
+import com.sap.oss.phosphor.fosstars.model.subject.oss.GitHubProject;
+import com.sap.oss.phosphor.fosstars.model.value.Languages;
+import com.sap.oss.phosphor.fosstars.model.value.PackageManagers;
+import com.sap.oss.phosphor.fosstars.model.value.ValueHashSet;
+import java.net.MalformedURLException;
+import org.junit.Test;
+
+public class SnykAdvisorTest {
+
+ @Test
+ public void testAdviseForSnyk() throws MalformedURLException {
+ final SnykAdvisor advisor = new SnykAdvisor(WITH_EMPTY_CONTEXT);
+ GitHubProject project = new GitHubProject("org", "test");
+
+ // no advice if no rating value is set
+ assertTrue(advisor.adviceFor(project).isEmpty());
+
+ Rating rating = RatingRepository.INSTANCE.rating(OssSecurityRating.class);
+ ValueSet values = new ValueHashSet();
+
+ // no advice for an unknown values
+ values.update(allUnknown(rating.score().allFeatures()));
+ values.update(LANGUAGES.value(Languages.of(GO)));
+ values.update(PACKAGE_MANAGERS.value(PackageManagers.from(GOMODULES)));
+ values.update(USES_GITHUB_FOR_DEVELOPMENT.value(true));
+ assertTrue(advisor.adviceFor(project).isEmpty());
+
+ values.update(USES_SNYK.value(true));
+ project.set(rating.calculate(values));
+ assertTrue(advisor.adviceFor(project).isEmpty());
+
+ values.update(USES_SNYK.value(false));
+ project.set(rating.calculate(values));
+ assertEquals(1, advisor.adviceFor(project).size());
+ assertEquals("You can create Snyk account and configure your project.",
+ advisor.adviceFor(project).get(0).content().text());
+ }
+
+ @Test
+ public void testAdviceWhenSnykScoreIsNotApplicable() throws MalformedURLException {
+ final SnykAdvisor advisor = new SnykAdvisor(WITH_EMPTY_CONTEXT);
+ final GitHubProject project = new GitHubProject("org", "test");
+
+ Rating rating = RatingRepository.INSTANCE.rating(OssSecurityRating.class);
+ ValueSet values = new ValueHashSet();
+ values.update(allUnknown(rating.score().allFeatures()));
+ values.update(USES_SNYK.value(false));
+ values.update(USES_GITHUB_FOR_DEVELOPMENT.value(true));
+ values.update(LANGUAGES.value(Languages.of(C)));
+ values.update(PACKAGE_MANAGERS.value(PackageManagers.from(OTHER)));
+ project.set(rating.calculate(values));
+ assertTrue(advisor.adviceFor(project).isEmpty());
+ }
+}
diff --git a/src/test/java/com/sap/oss/phosphor/fosstars/data/github/CodeOfConductGuidelineInfoTest.java b/src/test/java/com/sap/oss/phosphor/fosstars/data/github/CodeOfConductGuidelineInfoTest.java
index 11f85788f..2f831832a 100644
--- a/src/test/java/com/sap/oss/phosphor/fosstars/data/github/CodeOfConductGuidelineInfoTest.java
+++ b/src/test/java/com/sap/oss/phosphor/fosstars/data/github/CodeOfConductGuidelineInfoTest.java
@@ -13,8 +13,6 @@
import com.sap.oss.phosphor.fosstars.model.ValueSet;
import com.sap.oss.phosphor.fosstars.model.subject.oss.GitHubProject;
import java.io.IOException;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
diff --git a/src/test/java/com/sap/oss/phosphor/fosstars/data/github/UsesSnykTest.java b/src/test/java/com/sap/oss/phosphor/fosstars/data/github/UsesSnykTest.java
new file mode 100644
index 000000000..2058f15c1
--- /dev/null
+++ b/src/test/java/com/sap/oss/phosphor/fosstars/data/github/UsesSnykTest.java
@@ -0,0 +1,202 @@
+package com.sap.oss.phosphor.fosstars.data.github;
+
+import static com.sap.oss.phosphor.fosstars.data.github.TestGitHubDataFetcherHolder.TestGitHubDataFetcher.addForTesting;
+import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.HAS_OPEN_PULL_REQUEST_FROM_SNYK;
+import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_SNYK;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import com.sap.oss.phosphor.fosstars.data.SubjectValueCache;
+import com.sap.oss.phosphor.fosstars.model.Feature;
+import com.sap.oss.phosphor.fosstars.model.Value;
+import com.sap.oss.phosphor.fosstars.model.ValueSet;
+import com.sap.oss.phosphor.fosstars.model.subject.oss.GitHubProject;
+import com.sap.oss.phosphor.fosstars.model.value.ValueHashSet;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+import org.junit.Test;
+import org.kohsuke.github.GHPullRequest;
+import org.kohsuke.github.GHRepository;
+import org.kohsuke.github.GHUser;
+
+public class UsesSnykTest extends TestGitHubDataFetcherHolder {
+
+ private static final GitHubProject PROJECT = new GitHubProject("org", "test");
+
+ @Test
+ public void testWithSnykInAuthorName() throws IOException {
+ final List commits = new ArrayList<>();
+
+ Commit commit = mock(Commit.class);
+ when(commit.date()).thenReturn(new Date());
+ when(commit.authorName()).thenReturn("snyk");
+ when(commit.committerName()).thenReturn("GitHub");
+ commits.add(commit);
+
+ Commit otherCommit = mock(Commit.class);
+ when(otherCommit.date()).thenReturn(new Date());
+ when(otherCommit.authorName()).thenReturn("Mr. Test");
+ when(otherCommit.committerName()).thenReturn("Mr. Test");
+ commits.add(otherCommit);
+
+ LocalRepository repository = mock(LocalRepository.class);
+ when(repository.commitsAfter(any())).thenReturn(commits);
+ addForTesting(PROJECT, repository);
+
+ GHRepository githubRepository = mock(GHRepository.class);
+ when(fetcher.github().getRepository(any())).thenReturn(githubRepository);
+
+ testProvider(USES_SNYK.value(true), HAS_OPEN_PULL_REQUEST_FROM_SNYK.value(false));
+ }
+
+ @Test
+ public void testWithSnykInCommitterName() throws IOException {
+ final List commits = new ArrayList<>();
+
+ for (int i = 0; i < 1000; i++) {
+ Commit otherCommit = mock(Commit.class);
+ when(otherCommit.date()).thenReturn(new Date());
+ when(otherCommit.authorName()).thenReturn("Someone");
+ when(otherCommit.committerName()).thenReturn("Someone");
+ commits.add(otherCommit);
+ }
+
+ Commit commit = mock(Commit.class);
+ when(commit.date()).thenReturn(new Date());
+ when(commit.authorName()).thenReturn("GitHub");
+ when(commit.committerName()).thenReturn("snyk");
+ commits.add(commit);
+
+ LocalRepository repository = mock(LocalRepository.class);
+ when(repository.commitsAfter(any())).thenReturn(commits);
+ addForTesting(PROJECT, repository);
+
+ GHRepository githubRepository = mock(GHRepository.class);
+ when(fetcher.github().getRepository(any())).thenReturn(githubRepository);
+
+ testProvider(USES_SNYK.value(true), HAS_OPEN_PULL_REQUEST_FROM_SNYK.value(false));
+ }
+
+ @Test
+ public void testWithSnykInCommitMessage() throws IOException {
+ final List commits = new ArrayList<>();
+
+ Commit commit = mock(Commit.class);
+ when(commit.date()).thenReturn(new Date());
+ when(commit.authorName()).thenReturn("GitHub");
+ when(commit.committerName()).thenReturn("GitHub");
+ when(commit.message()).thenReturn(Arrays.asList("Commit message", "Signed-off-by: snyk"));
+ commits.add(commit);
+
+ Commit otherCommit = mock(Commit.class);
+ when(otherCommit.date()).thenReturn(new Date());
+ when(otherCommit.authorName()).thenReturn("Mr. Pink");
+ when(otherCommit.committerName()).thenReturn("Mr. Pink");
+ commits.add(otherCommit);
+
+ LocalRepository repository = mock(LocalRepository.class);
+ when(repository.commitsAfter(any())).thenReturn(commits);
+ addForTesting(PROJECT, repository);
+
+ GHRepository githubRepository = mock(GHRepository.class);
+ when(fetcher.github().getRepository(any())).thenReturn(githubRepository);
+
+ testProvider(USES_SNYK.value(true), HAS_OPEN_PULL_REQUEST_FROM_SNYK.value(false));
+ }
+
+ @Test
+ public void testWithSnykPolicyFile() throws IOException {
+ Path tempDirectory = Files.createTempDirectory(getClass().getName());
+ File snykPolicyFile = tempDirectory.resolve(".snyk").toFile();
+ List snykFilePaths = new ArrayList<>();
+ snykFilePaths.add(snykPolicyFile.toPath());
+ final LocalRepository repository = mock(LocalRepository.class);
+ when(repository.files(any())).thenReturn(snykFilePaths);
+ addForTesting(PROJECT, repository);
+
+ GHRepository githubRepository = mock(GHRepository.class);
+ when(fetcher.github().getRepository(any())).thenReturn(githubRepository);
+
+ testProvider(USES_SNYK.value(true), HAS_OPEN_PULL_REQUEST_FROM_SNYK.value(false));
+ }
+
+ @Test
+ public void testNoSnyk() throws IOException {
+ final List commits = new ArrayList<>();
+
+ Commit commit = mock(Commit.class);
+ when(commit.date()).thenReturn(new Date());
+ when(commit.authorName()).thenReturn("Mr. Orange");
+ when(commit.committerName()).thenReturn("Mr. Orange");
+ when(commit.message()).thenReturn(Arrays.asList("Commit message", "Signed-off-by: Mr. Pink"));
+ commits.add(commit);
+
+ commit = mock(Commit.class);
+ when(commit.date()).thenReturn(new Date());
+ when(commit.authorName()).thenReturn("Mr. Pink");
+ when(commit.committerName()).thenReturn("Mr. Pink");
+ when(commit.message()).thenReturn(Arrays.asList("Commit message", "Signed-off-by: Mr. Orange"));
+ commits.add(commit);
+
+ LocalRepository repository = mock(LocalRepository.class);
+ when(repository.files(any())).thenReturn(new ArrayList<>());
+ when(repository.commitsAfter(any())).thenReturn(commits);
+ addForTesting(PROJECT, repository);
+
+ GHRepository githubRepository = mock(GHRepository.class);
+ when(fetcher.github().getRepository(any())).thenReturn(githubRepository);
+
+ testProvider(USES_SNYK.value(false), HAS_OPEN_PULL_REQUEST_FROM_SNYK.value(false));
+ }
+
+ @Test
+ public void testWithOpenPullRequestFromSnyk() throws IOException {
+ Path tempDirectory = Files.createTempDirectory(getClass().getName());
+ File snykPolicyFile = tempDirectory.resolve(".snyk").toFile();
+ List snykFilePaths = new ArrayList<>();
+ snykFilePaths.add(snykPolicyFile.toPath());
+ final LocalRepository repository = mock(LocalRepository.class);
+ when(repository.files(any())).thenReturn(snykFilePaths);
+ addForTesting(PROJECT, repository);
+
+ GHRepository githubRepository = mock(GHRepository.class);
+ when(fetcher.github().getRepository(any())).thenReturn(githubRepository);
+ GHPullRequest pullRequest = mock(GHPullRequest.class);
+ GHUser user = mock(GHUser.class);
+ when(user.getName()).thenReturn("snyk");
+ when(pullRequest.getUser()).thenReturn(user);
+ when(githubRepository.getPullRequests(any()))
+ .thenReturn(Collections.singletonList(pullRequest));
+
+ testProvider(USES_SNYK.value(true), HAS_OPEN_PULL_REQUEST_FROM_SNYK.value(true));
+ }
+
+ private void testProvider(Value... expectedValues) throws IOException {
+ UsesSnyk provider = new UsesSnyk(fetcher);
+ provider.set(new SubjectValueCache());
+
+ ValueSet values = new ValueHashSet();
+ assertEquals(0, values.size());
+
+ provider.update(PROJECT, values);
+ assertEquals(expectedValues.length, values.size());
+ for (Value expectedValue : expectedValues) {
+ Feature feature = expectedValue.feature();
+ assertTrue(values.has(feature));
+ Optional> actualValue = values.of(feature);
+ assertTrue(actualValue.isPresent());
+ assertEquals(expectedValue, actualValue.get());
+ }
+ }
+}
diff --git a/src/test/java/com/sap/oss/phosphor/fosstars/model/score/oss/DependencyScanScoreTest.java b/src/test/java/com/sap/oss/phosphor/fosstars/model/score/oss/DependencyScanScoreTest.java
index 71d7aabc6..bb488565a 100644
--- a/src/test/java/com/sap/oss/phosphor/fosstars/model/score/oss/DependencyScanScoreTest.java
+++ b/src/test/java/com/sap/oss/phosphor/fosstars/model/score/oss/DependencyScanScoreTest.java
@@ -7,6 +7,7 @@
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.PACKAGE_MANAGERS;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_DEPENDABOT;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_GITHUB_FOR_DEVELOPMENT;
+import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_SNYK;
import static com.sap.oss.phosphor.fosstars.model.other.Utils.setOf;
import static com.sap.oss.phosphor.fosstars.model.value.Language.JAVA;
import static com.sap.oss.phosphor.fosstars.model.value.OwaspDependencyCheckUsage.MANDATORY;
@@ -33,12 +34,13 @@ public void testCalculate() {
OWASP_DEPENDENCY_CHECK_FAIL_CVSS_THRESHOLD.value(7.0),
USES_GITHUB_FOR_DEVELOPMENT.value(true),
USES_DEPENDABOT.value(true),
+ USES_SNYK.value(false),
LANGUAGES.value(Languages.of(JAVA)),
PACKAGE_MANAGERS.value(PackageManagers.from(MAVEN))
));
assertTrue(Score.INTERVAL.contains(scoreValue.get()));
- assertEquals(2, scoreValue.usedValues().size());
+ assertEquals(3, scoreValue.usedValues().size());
}
@Test
diff --git a/src/test/java/com/sap/oss/phosphor/fosstars/model/score/oss/OssSecurityScoreTest.java b/src/test/java/com/sap/oss/phosphor/fosstars/model/score/oss/OssSecurityScoreTest.java
index 9c39c11f7..ec41c3f04 100644
--- a/src/test/java/com/sap/oss/phosphor/fosstars/model/score/oss/OssSecurityScoreTest.java
+++ b/src/test/java/com/sap/oss/phosphor/fosstars/model/score/oss/OssSecurityScoreTest.java
@@ -36,6 +36,7 @@
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_OWASP_JAVA_ENCODER;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_OWASP_JAVA_HTML_SANITIZER;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_SIGNED_COMMITS;
+import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_SNYK;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_UNDEFINED_BEHAVIOR_SANITIZER;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.VULNERABILITIES_IN_PROJECT;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.WORST_LGTM_GRADE;
@@ -119,6 +120,7 @@ public static Set> defaultValues() {
WORST_LGTM_GRADE.value(LgtmGrade.B),
USES_NOHTTP.value(true),
USES_DEPENDABOT.value(true),
+ USES_SNYK.value(false),
USES_GITHUB_FOR_DEVELOPMENT.value(true),
LANGUAGES.value(Languages.of(JAVA)),
USES_ADDRESS_SANITIZER.value(false),
diff --git a/src/test/java/com/sap/oss/phosphor/fosstars/model/score/oss/SnykDependencyScanScoreTest.java b/src/test/java/com/sap/oss/phosphor/fosstars/model/score/oss/SnykDependencyScanScoreTest.java
new file mode 100644
index 000000000..c8e24ef61
--- /dev/null
+++ b/src/test/java/com/sap/oss/phosphor/fosstars/model/score/oss/SnykDependencyScanScoreTest.java
@@ -0,0 +1,64 @@
+package com.sap.oss.phosphor.fosstars.model.score.oss;
+
+import static com.sap.oss.phosphor.fosstars.TestUtils.DELTA;
+import static com.sap.oss.phosphor.fosstars.TestUtils.assertScore;
+import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.LANGUAGES;
+import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.PACKAGE_MANAGERS;
+import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_GITHUB_FOR_DEVELOPMENT;
+import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_SNYK;
+import static com.sap.oss.phosphor.fosstars.model.other.Utils.setOf;
+import static com.sap.oss.phosphor.fosstars.model.value.Language.GO;
+import static com.sap.oss.phosphor.fosstars.model.value.PackageManager.GOMODULES;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.sap.oss.phosphor.fosstars.model.Confidence;
+import com.sap.oss.phosphor.fosstars.model.Score;
+import com.sap.oss.phosphor.fosstars.model.other.Utils;
+import com.sap.oss.phosphor.fosstars.model.value.Languages;
+import com.sap.oss.phosphor.fosstars.model.value.PackageManagers;
+import com.sap.oss.phosphor.fosstars.model.value.ScoreValue;
+import org.junit.Test;
+
+public class SnykDependencyScanScoreTest {
+
+ private static final SnykDependencyScanScore SCORE = new SnykDependencyScanScore();
+
+ @Test
+ public void testCalculateWhenSnykIsUsed() {
+ assertScore(
+ Score.makeInterval(9, 10),
+ SCORE,
+ setOf(
+ USES_GITHUB_FOR_DEVELOPMENT.value(true),
+ USES_SNYK.value(true),
+ LANGUAGES.value(Languages.of(GO)),
+ PACKAGE_MANAGERS.value(PackageManagers.from(GOMODULES))));
+ }
+
+ @Test
+ public void testCalculateWhenSnykIsNotUsed() {
+ assertScore(
+ Score.makeInterval(0, 5),
+ SCORE,
+ setOf(
+ USES_GITHUB_FOR_DEVELOPMENT.value(true),
+ USES_SNYK.value(false),
+ LANGUAGES.value(Languages.of(GO)),
+ PACKAGE_MANAGERS.value(PackageManagers.from(GOMODULES))));
+ }
+
+ @Test
+ public void testCalculateWithAllUnknown() {
+ ScoreValue scoreValue = SCORE.calculate(Utils.allUnknown(SCORE.allFeatures()));
+ assertTrue(scoreValue.isUnknown());
+ assertEquals(Confidence.MIN, scoreValue.confidence(), DELTA);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testWithNoInfo() {
+ new DependencyScanScore().calculate();
+ }
+}
+
+
diff --git a/src/test/java/com/sap/oss/phosphor/fosstars/tool/format/OssSecurityRatingMarkdownFormatterTest.java b/src/test/java/com/sap/oss/phosphor/fosstars/tool/format/OssSecurityRatingMarkdownFormatterTest.java
index 2a1824544..02bb8e75e 100755
--- a/src/test/java/com/sap/oss/phosphor/fosstars/tool/format/OssSecurityRatingMarkdownFormatterTest.java
+++ b/src/test/java/com/sap/oss/phosphor/fosstars/tool/format/OssSecurityRatingMarkdownFormatterTest.java
@@ -36,6 +36,7 @@
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_OWASP_JAVA_ENCODER;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_OWASP_JAVA_HTML_SANITIZER;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_SIGNED_COMMITS;
+import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_SNYK;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_UNDEFINED_BEHAVIOR_SANITIZER;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.VULNERABILITIES_IN_PROJECT;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.WORST_LGTM_GRADE;
@@ -97,6 +98,7 @@ public class OssSecurityRatingMarkdownFormatterTest {
USES_GITHUB_FOR_DEVELOPMENT.value(false),
USES_NOHTTP.value(false),
USES_DEPENDABOT.value(false),
+ USES_SNYK.value(false),
USES_ADDRESS_SANITIZER.value(false),
USES_MEMORY_SANITIZER.value(false),
USES_UNDEFINED_BEHAVIOR_SANITIZER.value(false),
diff --git a/src/test/java/com/sap/oss/phosphor/fosstars/tool/format/PrettyPrinterTest.java b/src/test/java/com/sap/oss/phosphor/fosstars/tool/format/PrettyPrinterTest.java
index 5925f344a..5c755bbde 100644
--- a/src/test/java/com/sap/oss/phosphor/fosstars/tool/format/PrettyPrinterTest.java
+++ b/src/test/java/com/sap/oss/phosphor/fosstars/tool/format/PrettyPrinterTest.java
@@ -36,6 +36,7 @@
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_OWASP_JAVA_ENCODER;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_OWASP_JAVA_HTML_SANITIZER;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_SIGNED_COMMITS;
+import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_SNYK;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.USES_UNDEFINED_BEHAVIOR_SANITIZER;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.VULNERABILITIES_IN_PROJECT;
import static com.sap.oss.phosphor.fosstars.model.feature.oss.OssFeatures.WORST_LGTM_GRADE;
@@ -99,6 +100,7 @@ public class PrettyPrinterTest {
USES_GITHUB_FOR_DEVELOPMENT.value(false),
USES_NOHTTP.value(false),
USES_DEPENDABOT.value(false),
+ USES_SNYK.value(false),
USES_ADDRESS_SANITIZER.value(false),
USES_MEMORY_SANITIZER.value(false),
USES_UNDEFINED_BEHAVIOR_SANITIZER.value(false),
diff --git a/src/test/resources/com/sap/oss/phosphor/fosstars/model/rating/oss/OssArtifactSecurityRatingTestVectors.yml b/src/test/resources/com/sap/oss/phosphor/fosstars/model/rating/oss/OssArtifactSecurityRatingTestVectors.yml
index 90333949a..700f0d917 100644
--- a/src/test/resources/com/sap/oss/phosphor/fosstars/model/rating/oss/OssArtifactSecurityRatingTestVectors.yml
+++ b/src/test/resources/com/sap/oss/phosphor/fosstars/model/rating/oss/OssArtifactSecurityRatingTestVectors.yml
@@ -36,6 +36,11 @@ defaults:
type: "BooleanFeature"
name: "If a project uses Dependabot"
flag: true
+ - type: "BooleanValue"
+ feature:
+ type: "BooleanFeature"
+ name: "If a project uses Snyk"
+ flag: false
- type: "BooleanValue"
feature:
type: "BooleanFeature"
@@ -286,6 +291,10 @@ elements:
feature:
type: "BooleanFeature"
name: "If a project uses Dependabot"
+ - type: "UnknownValue"
+ feature:
+ type: "BooleanFeature"
+ name: "If a project uses Snyk"
- type: "UnknownValue"
feature:
type: "BooleanFeature"
diff --git a/src/test/resources/com/sap/oss/phosphor/fosstars/model/rating/oss/OssSecurityRatingTestVectors.yml b/src/test/resources/com/sap/oss/phosphor/fosstars/model/rating/oss/OssSecurityRatingTestVectors.yml
index 04af0a0d1..4b2c63cd9 100644
--- a/src/test/resources/com/sap/oss/phosphor/fosstars/model/rating/oss/OssSecurityRatingTestVectors.yml
+++ b/src/test/resources/com/sap/oss/phosphor/fosstars/model/rating/oss/OssSecurityRatingTestVectors.yml
@@ -7,6 +7,11 @@ defaults:
type: "BooleanFeature"
name: "If a project uses Dependabot"
flag: false
+- type: "BooleanValue"
+ feature:
+ type: "BooleanFeature"
+ name: "If a project uses Snyk"
+ flag: false
- type: "BooleanValue"
feature:
type: "BooleanFeature"
@@ -131,6 +136,10 @@ elements:
feature:
type: "BooleanFeature"
name: "If a project uses Dependabot"
+ - type: "UnknownValue"
+ feature:
+ type: "BooleanFeature"
+ name: "If a project uses Snyk"
- type: "UnknownValue"
feature:
type: "BooleanFeature"
diff --git a/src/test/resources/com/sap/oss/phosphor/fosstars/model/score/oss/DependabotScoreTestVectors.yml b/src/test/resources/com/sap/oss/phosphor/fosstars/model/score/oss/DependabotScoreTestVectors.yml
index 9f8311b7a..b574d2ee6 100644
--- a/src/test/resources/com/sap/oss/phosphor/fosstars/model/score/oss/DependabotScoreTestVectors.yml
+++ b/src/test/resources/com/sap/oss/phosphor/fosstars/model/score/oss/DependabotScoreTestVectors.yml
@@ -104,10 +104,10 @@ elements:
- "JAVA"
expectedScore:
type: "DoubleInterval"
- from: 6.0
+ from: 5.0
openLeft: false
negativeInfinity: false
- to: 9.0
+ to: 8.0
openRight: false
positiveInfinity: false
expectedLabel: null
diff --git a/src/test/resources/com/sap/oss/phosphor/fosstars/model/score/oss/DependencyScanScoreTestVectors.yml b/src/test/resources/com/sap/oss/phosphor/fosstars/model/score/oss/DependencyScanScoreTestVectors.yml
index 2a8d07cb7..f32d9ff58 100644
--- a/src/test/resources/com/sap/oss/phosphor/fosstars/model/score/oss/DependencyScanScoreTestVectors.yml
+++ b/src/test/resources/com/sap/oss/phosphor/fosstars/model/score/oss/DependencyScanScoreTestVectors.yml
@@ -1,7 +1,12 @@
---
# default values for test vectors
-defaults: []
+defaults:
+- type: "BooleanValue"
+ feature:
+ type: "BooleanFeature"
+ name: "If a project uses Snyk"
+ flag: false
# test vectors
elements:
@@ -21,6 +26,10 @@ elements:
feature:
type: "BooleanFeature"
name: "If a project uses Dependabot"
+ - type: "UnknownValue"
+ feature:
+ type: "BooleanFeature"
+ name: "If a project uses Snyk"
- type: "UnknownValue"
feature:
type: "BooleanFeature"
@@ -134,10 +143,10 @@ elements:
- "JAVA"
expectedScore:
type: "DoubleInterval"
- from: 5.0
+ from: 8.0
openLeft: false
negativeInfinity: false
- to: 8.0
+ to: 10.0
openRight: false
positiveInfinity: false
expectedLabel: null
diff --git a/src/test/resources/com/sap/oss/phosphor/fosstars/model/score/oss/ProjectSecurityAwarenessScoreTestVectors.yml b/src/test/resources/com/sap/oss/phosphor/fosstars/model/score/oss/ProjectSecurityAwarenessScoreTestVectors.yml
index 6d2e3c5da..37aed2815 100644
--- a/src/test/resources/com/sap/oss/phosphor/fosstars/model/score/oss/ProjectSecurityAwarenessScoreTestVectors.yml
+++ b/src/test/resources/com/sap/oss/phosphor/fosstars/model/score/oss/ProjectSecurityAwarenessScoreTestVectors.yml
@@ -5,6 +5,11 @@ defaults:
type: "BooleanFeature"
name: "If a project uses Dependabot"
flag: false
+- type: "BooleanValue"
+ feature:
+ type: "BooleanFeature"
+ name: "If a project uses Snyk"
+ flag: false
- type: "BooleanValue"
feature:
type: "BooleanFeature"
diff --git a/src/test/resources/com/sap/oss/phosphor/fosstars/model/score/oss/SnykDependencyScanScoreTestVectors.yml b/src/test/resources/com/sap/oss/phosphor/fosstars/model/score/oss/SnykDependencyScanScoreTestVectors.yml
new file mode 100644
index 000000000..5e041a657
--- /dev/null
+++ b/src/test/resources/com/sap/oss/phosphor/fosstars/model/score/oss/SnykDependencyScanScoreTestVectors.yml
@@ -0,0 +1,152 @@
+---
+
+# default values for test vectors
+defaults: []
+
+# test vectors
+elements:
+
+# all unknown
+- type: "StandardTestVector"
+ values:
+ - type: "UnknownValue"
+ feature:
+ type: "BooleanFeature"
+ name: "If a project uses Snyk"
+ - type: "UnknownValue"
+ feature:
+ type: "BooleanFeature"
+ name: "If a project uses GitHub as the main development platform"
+ - type: "UnknownValue"
+ feature:
+ type: "PackageManagersFeature"
+ name: "A set of package managers"
+ - type: "UnknownValue"
+ feature:
+ type: "LanguagesFeature"
+ name: "A set of programming languages"
+ expectedScore:
+ type: "DoubleInterval"
+ from: 0.0
+ openLeft: false
+ negativeInfinity: false
+ to: 1.0
+ openRight: false
+ positiveInfinity: false
+ expectedUnknownScore: true
+ expectedLabel: null
+ alias: "all_unknown"
+
+# very bad project
+- type: "StandardTestVector"
+ values:
+ - type: "BooleanValue"
+ feature:
+ type: "BooleanFeature"
+ name: "If a project uses Snyk"
+ flag: false
+ - type: "BooleanValue"
+ feature:
+ type: "BooleanFeature"
+ name: "If a project uses GitHub as the main development platform"
+ flag: false
+ - type: "PackageManagersValue"
+ feature:
+ type: "PackageManagersFeature"
+ name: "A set of package managers"
+ packageManagers:
+ packageManagers:
+ - "OTHER"
+ - type: "LanguagesValue"
+ feature:
+ type: "LanguagesFeature"
+ name: "A set of programming languages"
+ languages:
+ elements:
+ - "OTHER"
+ expectedScore:
+ type: "DoubleInterval"
+ from: 0.0
+ openLeft: false
+ negativeInfinity: false
+ to: 1.0
+ openRight: false
+ positiveInfinity: false
+ expectedLabel: null
+ alias: "very_bad"
+
+ # okay project
+- type: "StandardTestVector"
+ values:
+ - type: "BooleanValue"
+ feature:
+ type: "BooleanFeature"
+ name: "If a project uses Snyk"
+ flag: false
+ - type: "BooleanValue"
+ feature:
+ type: "BooleanFeature"
+ name: "If a project uses GitHub as the main development platform"
+ flag: true
+ - type: "PackageManagersValue"
+ feature:
+ type: "PackageManagersFeature"
+ name: "A set of package managers"
+ packageManagers:
+ packageManagers:
+ - "MAVEN"
+ - type: "LanguagesValue"
+ feature:
+ type: "LanguagesFeature"
+ name: "A set of programming languages"
+ languages:
+ elements:
+ - "JAVA"
+ expectedScore:
+ type: "DoubleInterval"
+ from: 5.0
+ openLeft: false
+ negativeInfinity: false
+ to: 8.0
+ openRight: false
+ positiveInfinity: false
+ expectedLabel: null
+ alias: "okay"
+
+# very good project
+- type: "StandardTestVector"
+ values:
+ - type: "BooleanValue"
+ feature:
+ type: "BooleanFeature"
+ name: "If a project uses Snyk"
+ flag: true
+ - type: "BooleanValue"
+ feature:
+ type: "BooleanFeature"
+ name: "If a project uses GitHub as the main development platform"
+ flag: true
+ - type: "PackageManagersValue"
+ feature:
+ type: "PackageManagersFeature"
+ name: "A set of package managers"
+ packageManagers:
+ packageManagers:
+ - "MAVEN"
+ - type: "LanguagesValue"
+ feature:
+ type: "LanguagesFeature"
+ name: "A set of programming languages"
+ languages:
+ elements:
+ - "JAVA"
+ expectedScore:
+ type: "DoubleInterval"
+ from: 9.0
+ openLeft: false
+ negativeInfinity: false
+ to: 10.0
+ openRight: false
+ positiveInfinity: false
+ expectedLabel: null
+ alias: "very_good"
diff --git a/src/test/resources/com/sap/oss/phosphor/fosstars/model/score/oss/VulnerabilityDiscoveryAndSecurityTestingScoreTestVectors.yml b/src/test/resources/com/sap/oss/phosphor/fosstars/model/score/oss/VulnerabilityDiscoveryAndSecurityTestingScoreTestVectors.yml
index d92541a7c..88012ddf9 100644
--- a/src/test/resources/com/sap/oss/phosphor/fosstars/model/score/oss/VulnerabilityDiscoveryAndSecurityTestingScoreTestVectors.yml
+++ b/src/test/resources/com/sap/oss/phosphor/fosstars/model/score/oss/VulnerabilityDiscoveryAndSecurityTestingScoreTestVectors.yml
@@ -1,5 +1,6 @@
---
defaults: []
+
elements:
- type: "StandardTestVector"
values:
@@ -15,6 +16,10 @@ elements:
feature:
type: "BooleanFeature"
name: "If a project uses Dependabot"
+ - type: "UnknownValue"
+ feature:
+ type: "BooleanFeature"
+ name: "If a project uses Snyk"
- type: "UnknownValue"
feature:
type: "BooleanFeature"
@@ -105,6 +110,10 @@ elements:
feature:
type: "BooleanFeature"
name: "If a project uses Dependabot"
+ - type: "UnknownValue"
+ feature:
+ type: "BooleanFeature"
+ name: "If a project uses Snyk"
- type: "VulnerabilitiesValue"
vulnerabilities:
entries:
diff --git a/src/test/shell/tool/github/lib.sh b/src/test/shell/tool/github/lib.sh
index 7c15b2848..e77f949da 100644
--- a/src/test/shell/tool/github/lib.sh
+++ b/src/test/shell/tool/github/lib.sh
@@ -24,6 +24,7 @@ declare -a project_security_default_expected_strings=(
'Figuring out how the project uses LGTM'
'Figuring out if the project uses OWASP security libraries'
'Checking how the project uses Dependabot'
+ 'Checking how the project uses Snyk'
'Figuring out if the project uses GitHub for development'
'Figuring out if the project uses sanitizers'
'Figuring out if the project uses FindSecBugs'
@@ -58,6 +59,7 @@ declare -a project_security_default_expected_strings=(
'Sub-score:....FindSecBugs score'
'Sub-score:....Dependency testing'
'Sub-score:....Dependabot score'
+ 'Sub-score:....Snyk score'
'Sub-score:....OWASP Dependency Check score'
'Sub-score:....Fuzzing'
'Sub-score:....Memory-safety testing'