From eb32ad378258bf146d159e1237d8760e0f012530 Mon Sep 17 00:00:00 2001 From: Mikhail Rusakovich Date: Wed, 22 Jun 2022 18:49:58 +0300 Subject: [PATCH 01/12] console multiple params support --- .../github/rusakovichma/tictaac/Launcher.java | 55 +++++++++++-------- .../tictaac/util/ConsoleUtil.java | 38 ++++++++----- .../tictaac/util/ConsoleUtilTest.java | 7 ++- 3 files changed, 62 insertions(+), 38 deletions(-) diff --git a/src/main/java/com/github/rusakovichma/tictaac/Launcher.java b/src/main/java/com/github/rusakovichma/tictaac/Launcher.java index fb9a767..7d93ef3 100644 --- a/src/main/java/com/github/rusakovichma/tictaac/Launcher.java +++ b/src/main/java/com/github/rusakovichma/tictaac/Launcher.java @@ -35,9 +35,7 @@ import java.io.FileNotFoundException; import java.io.IOException; -import java.util.Collection; -import java.util.Date; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; public class Launcher { @@ -113,38 +111,51 @@ private static void checkQualityGate(Map params, Collection params = ConsoleUtil.getParamsMap(args); - if (params.isEmpty() || !ConsoleUtil.hasOnlyAllowed(params) - || params.containsKey("help") || params.containsKey("-h")) { + final Map> multipleValueParams = ConsoleUtil.getParamsMap(args); + if (multipleValueParams.isEmpty() || !ConsoleUtil.hasOnlyAllowed(multipleValueParams) + || multipleValueParams.containsKey("help") || multipleValueParams.containsKey("-h")) { System.out.println(ResourceUtil.readResource("/help-info")); System.exit(0); } - if (params.containsKey("version") || params.containsKey("-v")) { + if (multipleValueParams.containsKey("version") || multipleValueParams.containsKey("-v")) { System.out.println(ResourceUtil.readResource("/version")); System.exit(0); } - ThreatRulesProvider rulesProvider = getRulesProvider(params); - Mitigator mitigator = getMitigator(params); + List threatModelsParams = multipleValueParams.get("threatModel"); - ThreatEngine threatEngine = getThreatEngine(rulesProvider, mitigator); + if (threatModelsParams == null) { + throw new IllegalStateException("Threat modeling file: '--threatModel %path_to_files_or_folder%' parameters should be provided"); + } - ThreatModelProvider threatModelProvider = getThreatModel(params); - ThreatsCollection threats = threatEngine.generateThreats(threatModelProvider.getModel()); - try { - getThreatsReporter(params).publish( - new ReportHeader( - threats.getName(), threats.getVersion(), new Date() - ), - threats.getThreats() - ); - } catch (IOException ex) { - throw new IllegalStateException("Cannot write threat model report to the file [" + params.get("out") + "]", ex); + for (String threatModelsParam : threatModelsParams) { + Map singleValueParams = ConsoleUtil.copySingleValueParamsWithDefinedArg(multipleValueParams, + "threatModel", threatModelsParam); + + ThreatRulesProvider rulesProvider = getRulesProvider(singleValueParams); + Mitigator mitigator = getMitigator(singleValueParams); + + ThreatEngine threatEngine = getThreatEngine(rulesProvider, mitigator); + + ThreatModelProvider threatModelProvider = getThreatModel(singleValueParams); + ThreatsCollection threats = threatEngine.generateThreats(threatModelProvider.getModel()); + + try { + getThreatsReporter(singleValueParams).publish( + new ReportHeader( + threats.getName(), threats.getVersion(), new Date() + ), + threats.getThreats() + ); + } catch (IOException ex) { + throw new IllegalStateException("Cannot write threat model report to the file [" + singleValueParams.get("out") + "]", ex); + } + + checkQualityGate(singleValueParams, threats.getThreats()); } - checkQualityGate(params, threats.getThreats()); } } diff --git a/src/main/java/com/github/rusakovichma/tictaac/util/ConsoleUtil.java b/src/main/java/com/github/rusakovichma/tictaac/util/ConsoleUtil.java index 83f8b9f..4d15f56 100644 --- a/src/main/java/com/github/rusakovichma/tictaac/util/ConsoleUtil.java +++ b/src/main/java/com/github/rusakovichma/tictaac/util/ConsoleUtil.java @@ -33,7 +33,7 @@ private ConsoleUtil() { private static class ConsoleParam { private String key; - private String value; + private List values = new ArrayList<>(); public ConsoleParam(String key) { this.key = key; @@ -47,12 +47,12 @@ public void setKey(String key) { this.key = key; } - public String getValue() { - return value; + public List getValues() { + return values; } - public void setValue(String value) { - this.value = value; + public void addValue(String value) { + this.values.add(value); } @Override @@ -60,16 +60,16 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ConsoleParam that = (ConsoleParam) o; - return Objects.equals(key, that.key) && Objects.equals(value, that.value); + return Objects.equals(key, that.key) && Objects.equals(values, that.values); } @Override public int hashCode() { - return Objects.hash(key, value); + return Objects.hash(key, values); } } - public static Map getParamsMap(String[] args) { + public static Map> getParamsMap(String[] args) { Stack params = new Stack<>(); if (args != null && args.length != 0) { for (int i = 0; i < args.length; i++) { @@ -79,7 +79,7 @@ public static Map getParamsMap(String[] args) { .replaceFirst("--", ""))); } else { if (!params.empty()) { - params.peek().setValue( + params.peek().addValue( args[i].trim().replaceAll("\"", "") .replaceAll("'", "")); } @@ -87,17 +87,17 @@ public static Map getParamsMap(String[] args) { } } - Map paramsMap = new HashMap<>(); + Map> paramsMap = new HashMap<>(); while (!params.empty()) { ConsoleParam param = params.pop(); - paramsMap.put(param.getKey(), param.getValue()); + paramsMap.put(param.getKey(), param.getValues()); } return paramsMap; } - public static boolean hasOnlyAllowed(Map params) { - for (Map.Entry entry : params.entrySet()) { + public static boolean hasOnlyAllowed(Map> params) { + for (Map.Entry> entry : params.entrySet()) { if (!PARAMS_WHITELIST.stream() .anyMatch(entry.getKey()::equalsIgnoreCase)) { return false; @@ -106,4 +106,16 @@ public static boolean hasOnlyAllowed(Map params) { return true; } + public static Map copySingleValueParamsWithDefinedArg(Map> params, + String paramName, String paramValue) { + Map singleValueParams = new HashMap<>(); + for (Map.Entry> entry : params.entrySet()) { + if (entry.getValue() != null) { + String value = paramName.equalsIgnoreCase(entry.getKey()) ? paramValue : entry.getValue().get(0); + singleValueParams.put(entry.getKey(), value); + } + } + return singleValueParams; + } + } diff --git a/src/test/java/com/github/rusakovichma/tictaac/util/ConsoleUtilTest.java b/src/test/java/com/github/rusakovichma/tictaac/util/ConsoleUtilTest.java index 0d234a0..2f45e77 100644 --- a/src/test/java/com/github/rusakovichma/tictaac/util/ConsoleUtilTest.java +++ b/src/test/java/com/github/rusakovichma/tictaac/util/ConsoleUtilTest.java @@ -2,6 +2,7 @@ import org.junit.jupiter.api.Test; +import java.util.List; import java.util.Map; import static org.junit.jupiter.api.Assertions.*; @@ -15,7 +16,7 @@ void getParams() { "--threatsLibraryAccessUsername", "username", "--threatsLibraryAccessPassword", "pass123456", "--mitigations", "\"${WORKSPACE}/mitigations.yml\"", "--outFormat", "html", "--out", "${WORKSPACE}/reports"}; - Map paramsMap = ConsoleUtil.getParamsMap(params); + Map> paramsMap = ConsoleUtil.getParamsMap(params); assertTrue(paramsMap.size() == 8); } @@ -26,7 +27,7 @@ void getParamsWhitelistPass() { "--threatsLibraryAccessUsername", "username", "--threatsLibraryAccessPassword", "pass123456", "--mitigations", "\"${WORKSPACE}/mitigations.yml\"", "--outFormat", "html", "--out", "${WORKSPACE}/reports"}; - Map paramsMap = ConsoleUtil.getParamsMap(params); + Map> paramsMap = ConsoleUtil.getParamsMap(params); assertTrue(ConsoleUtil.hasOnlyAllowed(paramsMap)); } @@ -37,7 +38,7 @@ void getParamsWhitelistNotPassed() { "--threatsLibraryAccessUsername", "username", "--threatsLibraryAccessPassword", "pass123456", "--mitigations", "\"${WORKSPACE}/mitigations.yml\"", "--outFormat", "html", "--out", "${WORKSPACE}/reports"}; - Map paramsMap = ConsoleUtil.getParamsMap(params); + Map> paramsMap = ConsoleUtil.getParamsMap(params); assertFalse(ConsoleUtil.hasOnlyAllowed(paramsMap)); } } \ No newline at end of file From ff308766f34530ed93eef562cdff57398d4960c9 Mon Sep 17 00:00:00 2001 From: Mikhail Rusakovich Date: Thu, 23 Jun 2022 09:18:36 +0300 Subject: [PATCH 02/12] multiple params support tests, launcher exception message edit --- .../github/rusakovichma/tictaac/Launcher.java | 2 +- .../tictaac/util/ConsoleUtilTest.java | 26 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/github/rusakovichma/tictaac/Launcher.java b/src/main/java/com/github/rusakovichma/tictaac/Launcher.java index 7d93ef3..573976f 100644 --- a/src/main/java/com/github/rusakovichma/tictaac/Launcher.java +++ b/src/main/java/com/github/rusakovichma/tictaac/Launcher.java @@ -126,7 +126,7 @@ public static void main(String[] args) { List threatModelsParams = multipleValueParams.get("threatModel"); if (threatModelsParams == null) { - throw new IllegalStateException("Threat modeling file: '--threatModel %path_to_files_or_folder%' parameters should be provided"); + throw new IllegalStateException("Threat modeling files: '--threatModel %path_to_files_or_folder%' parameters should be provided"); } diff --git a/src/test/java/com/github/rusakovichma/tictaac/util/ConsoleUtilTest.java b/src/test/java/com/github/rusakovichma/tictaac/util/ConsoleUtilTest.java index 2f45e77..f68be20 100644 --- a/src/test/java/com/github/rusakovichma/tictaac/util/ConsoleUtilTest.java +++ b/src/test/java/com/github/rusakovichma/tictaac/util/ConsoleUtilTest.java @@ -41,4 +41,30 @@ void getParamsWhitelistNotPassed() { Map> paramsMap = ConsoleUtil.getParamsMap(params); assertFalse(ConsoleUtil.hasOnlyAllowed(paramsMap)); } + + @Test + void getParamsWithMultipleValues() { + String[] params = {"--threatModel", "${WORKSPACE}/threat-model.yml", "${WORKSPACE}/threat-model-two.yml", "threat-model-three.yml", + "--failOnThreatRisk", "High", "--threatsLibrary", "https://my-site.com/my-threats-library.yml", + "--threatsLibraryAccessUsername", "username", "--threatsLibraryAccessPassword", "pass123456", + "--mitigations", "\"${WORKSPACE}/mitigations.yml\"", "--outFormat", "html", "--out", "${WORKSPACE}/reports"}; + + Map> paramsMap = ConsoleUtil.getParamsMap(params); + assertTrue(paramsMap.get("threatModel").size() == 3); + } + + @Test + void copySingleValueParamsWithDefinedArg() { + String[] params = {"--threatModel", "${WORKSPACE}/threat-model.yml", "${WORKSPACE}/threat-model-two.yml", "threat-model-three.yml", + "--failOnThreatRisk", "High", "--threatsLibrary", "https://my-site.com/my-threats-library.yml", + "--threatsLibraryAccessUsername", "username", "--threatsLibraryAccessPassword", "pass123456", + "--mitigations", "\"${WORKSPACE}/mitigations.yml\"", "--outFormat", "html", "--out", "${WORKSPACE}/reports"}; + + Map> paramsMap = ConsoleUtil.getParamsMap(params); + Map singleValueMap = ConsoleUtil.copySingleValueParamsWithDefinedArg(paramsMap, + "threatModel", "threat-model-three.yml"); + assertTrue(singleValueMap.size() == 8); + assertTrue(singleValueMap.get("threatModel").equals("threat-model-three.yml")); + + } } \ No newline at end of file From 00f22c708eaa595e601fcb55a52f927b291bb6e6 Mon Sep 17 00:00:00 2001 From: Mikhail Rusakovich Date: Thu, 23 Jun 2022 11:34:38 +0300 Subject: [PATCH 03/12] threat modeling files filter and tests --- .../github/rusakovichma/tictaac/Launcher.java | 2 +- .../provider/reader/ThreatModelFilter.java | 18 ++++++++++++++++++ .../rusakovichma/tictaac/util/FileUtil.java | 14 ++++++++++++++ .../provider/reader/ThreatModelFilterTest.java | 18 ++++++++++++++++++ 4 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/github/rusakovichma/tictaac/provider/reader/ThreatModelFilter.java create mode 100644 src/test/java/com/github/rusakovichma/tictaac/provider/reader/ThreatModelFilterTest.java diff --git a/src/main/java/com/github/rusakovichma/tictaac/Launcher.java b/src/main/java/com/github/rusakovichma/tictaac/Launcher.java index 573976f..b042506 100644 --- a/src/main/java/com/github/rusakovichma/tictaac/Launcher.java +++ b/src/main/java/com/github/rusakovichma/tictaac/Launcher.java @@ -125,7 +125,7 @@ public static void main(String[] args) { List threatModelsParams = multipleValueParams.get("threatModel"); - if (threatModelsParams == null) { + if (threatModelsParams == null || threatModelsParams.isEmpty()) { throw new IllegalStateException("Threat modeling files: '--threatModel %path_to_files_or_folder%' parameters should be provided"); } diff --git a/src/main/java/com/github/rusakovichma/tictaac/provider/reader/ThreatModelFilter.java b/src/main/java/com/github/rusakovichma/tictaac/provider/reader/ThreatModelFilter.java new file mode 100644 index 0000000..3cfab02 --- /dev/null +++ b/src/main/java/com/github/rusakovichma/tictaac/provider/reader/ThreatModelFilter.java @@ -0,0 +1,18 @@ +package com.github.rusakovichma.tictaac.provider.reader; + +import com.github.rusakovichma.tictaac.util.FileUtil; + +import java.io.File; +import java.io.FileFilter; + +public class ThreatModelFilter implements FileFilter { + + @Override + public boolean accept(File modelFile) { + if (!modelFile.getName().toLowerCase().endsWith(".yml")) { + return false; + } + return FileUtil.findString(modelFile, "elements:") + && FileUtil.findString(modelFile, "data-flows:"); + } +} diff --git a/src/main/java/com/github/rusakovichma/tictaac/util/FileUtil.java b/src/main/java/com/github/rusakovichma/tictaac/util/FileUtil.java index 8bd97b5..f093377 100644 --- a/src/main/java/com/github/rusakovichma/tictaac/util/FileUtil.java +++ b/src/main/java/com/github/rusakovichma/tictaac/util/FileUtil.java @@ -21,6 +21,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Paths; import java.util.function.Consumer; @@ -44,4 +45,17 @@ public static InputStream fileToInputStream(String filePath) return new FileInputStream(file); } + public static boolean findString(File file, String string) { + try { + try (Stream lines = Files.lines(file.toPath(), Charset.defaultCharset())) { + return (lines.filter(line -> line.contains(string)) + .findFirst() + .get()) != null; + } + } catch (Exception ex) { + return false; + } + } + + } diff --git a/src/test/java/com/github/rusakovichma/tictaac/provider/reader/ThreatModelFilterTest.java b/src/test/java/com/github/rusakovichma/tictaac/provider/reader/ThreatModelFilterTest.java new file mode 100644 index 0000000..3c0468c --- /dev/null +++ b/src/test/java/com/github/rusakovichma/tictaac/provider/reader/ThreatModelFilterTest.java @@ -0,0 +1,18 @@ +package com.github.rusakovichma.tictaac.provider.reader; + +import org.junit.jupiter.api.Test; + +import java.io.File; + +import static org.junit.jupiter.api.Assertions.*; + +class ThreatModelFilterTest { + + @Test + void accept() { + File dir = new File("src/test/resources"); + File[] modelFiles = dir.listFiles(new ThreatModelFilter()); + + assertTrue(modelFiles.length == 5); + } +} \ No newline at end of file From 2690f2cf51797ee7050e902a0c1576997d0f6ab6 Mon Sep 17 00:00:00 2001 From: Mikhail Rusakovich Date: Thu, 23 Jun 2022 12:21:17 +0300 Subject: [PATCH 04/12] Mitigations filter --- .../provider/reader/MitigationsFilter.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/main/java/com/github/rusakovichma/tictaac/provider/reader/MitigationsFilter.java diff --git a/src/main/java/com/github/rusakovichma/tictaac/provider/reader/MitigationsFilter.java b/src/main/java/com/github/rusakovichma/tictaac/provider/reader/MitigationsFilter.java new file mode 100644 index 0000000..192a745 --- /dev/null +++ b/src/main/java/com/github/rusakovichma/tictaac/provider/reader/MitigationsFilter.java @@ -0,0 +1,18 @@ +package com.github.rusakovichma.tictaac.provider.reader; + +import com.github.rusakovichma.tictaac.util.FileUtil; + +import java.io.File; +import java.io.FileFilter; + +public class MitigationsFilter implements FileFilter { + + @Override + public boolean accept(File mitigationsFile) { + if (!mitigationsFile.getName().toLowerCase().endsWith(".yml")) { + return false; + } + return FileUtil.findString(mitigationsFile, "mitigated:"); + } + +} From 41a1ec7cc8319f3862273a5d67d0834448e3a86c Mon Sep 17 00:00:00 2001 From: Mikhail Rusakovich Date: Wed, 29 Jun 2022 12:24:15 +0300 Subject: [PATCH 05/12] threat Models Files Only Param --- .../github/rusakovichma/tictaac/Launcher.java | 5 ++- .../rusakovichma/tictaac/util/FileUtil.java | 35 ++++++++++++++++--- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/github/rusakovichma/tictaac/Launcher.java b/src/main/java/com/github/rusakovichma/tictaac/Launcher.java index b042506..e71c992 100644 --- a/src/main/java/com/github/rusakovichma/tictaac/Launcher.java +++ b/src/main/java/com/github/rusakovichma/tictaac/Launcher.java @@ -27,10 +27,12 @@ import com.github.rusakovichma.tictaac.provider.mitigation.*; import com.github.rusakovichma.tictaac.provider.model.StandardThreatModelProvider; import com.github.rusakovichma.tictaac.provider.model.ThreatModelProvider; +import com.github.rusakovichma.tictaac.provider.reader.ThreatModelFilter; import com.github.rusakovichma.tictaac.provider.rules.StandardThreatRulesProvider; import com.github.rusakovichma.tictaac.provider.rules.ThreatRulesProvider; import com.github.rusakovichma.tictaac.reporter.*; import com.github.rusakovichma.tictaac.util.ConsoleUtil; +import com.github.rusakovichma.tictaac.util.FileUtil; import com.github.rusakovichma.tictaac.util.ResourceUtil; import java.io.FileNotFoundException; @@ -129,8 +131,9 @@ public static void main(String[] args) { throw new IllegalStateException("Threat modeling files: '--threatModel %path_to_files_or_folder%' parameters should be provided"); } + List threatModelsFilesOnlyParams = FileUtil.extractFiles(threatModelsParams, new ThreatModelFilter()); - for (String threatModelsParam : threatModelsParams) { + for (String threatModelsParam : threatModelsFilesOnlyParams) { Map singleValueParams = ConsoleUtil.copySingleValueParamsWithDefinedArg(multipleValueParams, "threatModel", threatModelsParam); diff --git a/src/main/java/com/github/rusakovichma/tictaac/util/FileUtil.java b/src/main/java/com/github/rusakovichma/tictaac/util/FileUtil.java index f093377..4c86187 100644 --- a/src/main/java/com/github/rusakovichma/tictaac/util/FileUtil.java +++ b/src/main/java/com/github/rusakovichma/tictaac/util/FileUtil.java @@ -17,13 +17,13 @@ */ package com.github.rusakovichma.tictaac.util; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; +import java.io.*; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.function.Consumer; import java.util.stream.Stream; @@ -57,5 +57,32 @@ public static boolean findString(File file, String string) { } } + public static List extractFiles(List paths, FileFilter filter) { + if (paths == null || paths.isEmpty()) { + return Collections.EMPTY_LIST; + } + + List extractedFiles = new ArrayList<>(); + + for (String path : paths) { + File file = new File(path); + if (file.exists()) { + if (file.isFile()) { + extractedFiles.add(path); + } else { + File[] filesInFolder = (filter != null) + ? file.listFiles(filter) : file.listFiles(); + if (filesInFolder != null && filesInFolder.length != 0) { + for (File fileInFolder : filesInFolder) { + extractedFiles.add(fileInFolder.getAbsolutePath()); + } + } + } + } + } + + return extractedFiles; + } + } From ae219b368190bbd98ee4817970fea52675e3a538 Mon Sep 17 00:00:00 2001 From: Mikhail Rusakovich Date: Fri, 1 Jul 2022 20:20:34 +0300 Subject: [PATCH 06/12] required fileutils add --- .../rusakovichma/tictaac/util/FileUtil.java | 22 ++++++++++++++++ .../tictaac/util/FileUtilTest.java | 26 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/src/main/java/com/github/rusakovichma/tictaac/util/FileUtil.java b/src/main/java/com/github/rusakovichma/tictaac/util/FileUtil.java index 4c86187..6447ce3 100644 --- a/src/main/java/com/github/rusakovichma/tictaac/util/FileUtil.java +++ b/src/main/java/com/github/rusakovichma/tictaac/util/FileUtil.java @@ -20,6 +20,7 @@ import java.io.*; import java.nio.charset.Charset; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; @@ -84,5 +85,26 @@ public static List extractFiles(List paths, FileFilter filter) { return extractedFiles; } + public static String getFilenameWithoutExtensionFromPath(String filePath) { + if (filePath == null) return null; + + Path path = Paths.get(filePath); + String fileName = path.getFileName().toString(); + + int extPosition = fileName.lastIndexOf("."); + if (extPosition == -1) return fileName; + + return fileName.substring(0, extPosition); + } + + public static String getParentFolderFromFilePath(String filePath) { + if (filePath == null) return null; + + Path path = Paths.get(filePath); + String fileName = path.getFileName().toString(); + + return filePath.replaceAll(fileName, ""); + } + } diff --git a/src/test/java/com/github/rusakovichma/tictaac/util/FileUtilTest.java b/src/test/java/com/github/rusakovichma/tictaac/util/FileUtilTest.java index 16c23ae..2adc53f 100644 --- a/src/test/java/com/github/rusakovichma/tictaac/util/FileUtilTest.java +++ b/src/test/java/com/github/rusakovichma/tictaac/util/FileUtilTest.java @@ -1,8 +1,11 @@ package com.github.rusakovichma.tictaac.util; +import com.github.rusakovichma.tictaac.provider.reader.ThreatModelFilter; import org.junit.jupiter.api.Test; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import java.util.function.Consumer; import static org.junit.jupiter.api.Assertions.*; @@ -14,4 +17,27 @@ void readLineByLine() throws IOException { Consumer lineReader = string -> assertTrue(!string.isEmpty()); FileUtil.readLineByLine("src/test/resources/threat-model-test.yml", lineReader); } + + @Test + void extractFiles() throws IOException { + List paths = new ArrayList<>(); + + paths.add("src/test/resources/threat-model-test.yml"); + paths.add("src/test/resources/"); + + List threatModels = FileUtil.extractFiles(paths, new ThreatModelFilter()); + assertEquals(6, threatModels.size()); + } + + @Test + void getFilenameWithoutExtensionFromPath() { + String filename = FileUtil.getFilenameWithoutExtensionFromPath("src/test/resources/threat-model-test.yml"); + assertEquals("threat-model-test", filename); + } + + @Test + void getParentFolderFromFilePath() { + String parent = FileUtil.getParentFolderFromFilePath("src/test/resources/threat-model-test.yml"); + assertEquals("src/test/resources/", parent); + } } \ No newline at end of file From 0240174019567978315b35dd87cf719fd9cfb712 Mon Sep 17 00:00:00 2001 From: Mikhail Rusakovich Date: Sun, 3 Jul 2022 16:42:20 +0300 Subject: [PATCH 07/12] guaity gate multiple threat models check --- .../github/rusakovichma/tictaac/Launcher.java | 42 ++++++++++++------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/github/rusakovichma/tictaac/Launcher.java b/src/main/java/com/github/rusakovichma/tictaac/Launcher.java index e71c992..ff8afb2 100644 --- a/src/main/java/com/github/rusakovichma/tictaac/Launcher.java +++ b/src/main/java/com/github/rusakovichma/tictaac/Launcher.java @@ -94,19 +94,29 @@ private static ThreatsReporter getThreatsReporter(Map params) { } } - private static void checkQualityGate(Map params, Collection threats) { - String failOnThreatRiskParam = params.get("failOnThreatRisk"); - if (failOnThreatRiskParam != null) { - ThreatRisk qualityGate = ThreatRisk.fromString(failOnThreatRiskParam.trim()); + private static void checkQualityGate(Map> params, Map> threats) { + List failOnThreatRiskParam = params.get("failOnThreatRisk"); + if (failOnThreatRiskParam != null && failOnThreatRiskParam.size() != 0) { + ThreatRisk qualityGate = ThreatRisk.fromString(failOnThreatRiskParam.get(0).trim()); if (qualityGate != ThreatRisk.Undefined) { - String notCompliantThreats = threats.stream() - .filter(threat -> threat.getRisk().getOrder() >= qualityGate.getOrder()) - .filter(threat -> threat.getMitigationStatus() == MitigationStatus.NotMitigated) - .map(threat -> threat.getId()) - .collect(Collectors.joining(", ")); - - if (notCompliantThreats != null && !notCompliantThreats.isEmpty()) { - throw new QualityGateFailed(String.format("Non-compliant threats found [%s]", notCompliantThreats)); + StringBuilder nonComplianceAccumulator = new StringBuilder(); + + for (Map.Entry> entry : threats.entrySet()) { + String notCompliantThreats = entry.getValue().stream() + .filter(threat -> threat.getRisk().getOrder() >= qualityGate.getOrder()) + .filter(threat -> threat.getMitigationStatus() == MitigationStatus.NotMitigated) + .map(threat -> threat.getId()) + .collect(Collectors.joining(", ")); + + if (notCompliantThreats != null && !notCompliantThreats.isEmpty()) { + nonComplianceAccumulator.append(String.format("%s: [%s]", entry.getKey(), notCompliantThreats)) + .append(System.lineSeparator()); + } + } + + if (nonComplianceAccumulator.length() != 0) { + throw new QualityGateFailed(String.format("Non-compliant threats found: ", + nonComplianceAccumulator.toString())); } } } @@ -132,6 +142,7 @@ public static void main(String[] args) { } List threatModelsFilesOnlyParams = FileUtil.extractFiles(threatModelsParams, new ThreatModelFilter()); + Map> modelThreats = new LinkedHashMap<>(); for (String threatModelsParam : threatModelsFilesOnlyParams) { Map singleValueParams = ConsoleUtil.copySingleValueParamsWithDefinedArg(multipleValueParams, @@ -145,6 +156,8 @@ public static void main(String[] args) { ThreatModelProvider threatModelProvider = getThreatModel(singleValueParams); ThreatsCollection threats = threatEngine.generateThreats(threatModelProvider.getModel()); + modelThreats.put(threatModelsParam, threats.getThreats()); + try { getThreatsReporter(singleValueParams).publish( new ReportHeader( @@ -153,12 +166,11 @@ public static void main(String[] args) { threats.getThreats() ); } catch (IOException ex) { - throw new IllegalStateException("Cannot write threat model report to the file [" + singleValueParams.get("out") + "]", ex); + throw new IllegalStateException("Cannot write threat model report to the path [" + singleValueParams.get("out") + "]", ex); } - - checkQualityGate(singleValueParams, threats.getThreats()); } + checkQualityGate(multipleValueParams, modelThreats); } } From b9c2d722831c0ce8ca9e65dda0b102dccdc74d64 Mon Sep 17 00:00:00 2001 From: Mikhail Rusakovich Date: Sun, 3 Jul 2022 18:02:08 +0300 Subject: [PATCH 08/12] mitigators multiple variants processing --- .../github/rusakovichma/tictaac/Launcher.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/main/java/com/github/rusakovichma/tictaac/Launcher.java b/src/main/java/com/github/rusakovichma/tictaac/Launcher.java index ff8afb2..5f13618 100644 --- a/src/main/java/com/github/rusakovichma/tictaac/Launcher.java +++ b/src/main/java/com/github/rusakovichma/tictaac/Launcher.java @@ -35,6 +35,7 @@ import com.github.rusakovichma.tictaac.util.FileUtil; import com.github.rusakovichma.tictaac.util.ResourceUtil; +import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.*; @@ -64,6 +65,34 @@ private static ThreatModelProvider getThreatModel(Map params) { private static Mitigator getMitigator(Map params) { String mitigationsPath = params.get("mitigations"); + + String threatModelPath = params.get("threatModel"); + if (threatModelPath != null || !threatModelPath.isEmpty()) { + String threatModelDir = FileUtil.getParentFolderFromFilePath(threatModelPath); + String threatModelName = FileUtil.getFilenameWithoutExtensionFromPath(threatModelPath); + + File threatModelMitigationsFile = new File( + threatModelDir + File.separator + threatModelName + "-mitigations.yml"); + if (threatModelMitigationsFile.exists()) { + mitigationsPath = threatModelMitigationsFile.getAbsolutePath(); + } + } + + if (mitigationsPath != null && !mitigationsPath.isEmpty()) { + File mitigationsFile = new File(mitigationsPath); + if (mitigationsFile.exists() && mitigationsFile.isDirectory()) { + if (threatModelPath != null || !threatModelPath.isEmpty()) { + String threatModelName = FileUtil.getFilenameWithoutExtensionFromPath(threatModelPath); + + File threatModelMitigationsFile = new File( + mitigationsFile.getAbsolutePath() + File.separator + threatModelName + "-mitigations.yml"); + if (threatModelMitigationsFile.exists()) { + mitigationsPath = threatModelMitigationsFile.getAbsolutePath(); + } + } + } + } + if (mitigationsPath == null) { return new DullMitigator(); } From 0e50c523c06b8962a406f809e63a288e395509d0 Mon Sep 17 00:00:00 2001 From: Mikhail Rusakovich Date: Sun, 3 Jul 2022 21:21:24 +0300 Subject: [PATCH 09/12] reporter multiple threat models support, v1.2.2 --- pom.xml | 4 ++-- .../java/com/github/rusakovichma/tictaac/Launcher.java | 10 +++++++++- .../tictaac/reporter/FileStreamThreatsReporter.java | 6 ++---- src/main/resources/version | 2 +- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index 85f1a62..16430cc 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.github.rusakovichma tictaac - 1.1.4 + 1.2.2 TicTaaC https://github.com/rusakovichma/TicTaaC.git @@ -30,7 +30,7 @@ scm:git:https://github.com/rusakovichma/TicTaaC.git https://github.com/rusakovichma/TicTaaC scm:git:https://github.com/rusakovichma/TicTaaC.git - v1.0.3 + v1.2.2 github diff --git a/src/main/java/com/github/rusakovichma/tictaac/Launcher.java b/src/main/java/com/github/rusakovichma/tictaac/Launcher.java index 5f13618..7e4b051 100644 --- a/src/main/java/com/github/rusakovichma/tictaac/Launcher.java +++ b/src/main/java/com/github/rusakovichma/tictaac/Launcher.java @@ -43,6 +43,7 @@ public class Launcher { + private static final String DEFAULT_REPORT_NAME = "threat-model-report"; private static final String OUT_PATH_DEFAULT = "."; private static final ReportFormat DEFAULT_OUT_FORMAT = ReportFormat.html; private static final String DEFAULT_THREAT_LIBRARY = "classpath:/threats-library/default-threats-library.yml"; @@ -116,8 +117,15 @@ private static ThreatsReporter getThreatsReporter(Map params) { if (outFormat == null) { outFormat = DEFAULT_OUT_FORMAT; } + + String reportName = DEFAULT_REPORT_NAME; + String threatModelPath = params.get("threatModel"); + if (threatModelPath != null || !threatModelPath.isEmpty()) { + reportName = FileUtil.getFilenameWithoutExtensionFromPath(threatModelPath); + } + try { - return new FileStreamThreatsReporter(outPath, outFormat); + return new FileStreamThreatsReporter(outPath, reportName, outFormat); } catch (FileNotFoundException ex) { throw new IllegalStateException(ex); } diff --git a/src/main/java/com/github/rusakovichma/tictaac/reporter/FileStreamThreatsReporter.java b/src/main/java/com/github/rusakovichma/tictaac/reporter/FileStreamThreatsReporter.java index bae81ac..957d385 100644 --- a/src/main/java/com/github/rusakovichma/tictaac/reporter/FileStreamThreatsReporter.java +++ b/src/main/java/com/github/rusakovichma/tictaac/reporter/FileStreamThreatsReporter.java @@ -23,14 +23,12 @@ public class FileStreamThreatsReporter extends StreamThreatsReporter { - private static final String REPORT_NAME = "threat-model-report"; - - public FileStreamThreatsReporter(String reportOut, ReportFormat reportFormat) + public FileStreamThreatsReporter(String reportOut, String reportName, ReportFormat reportFormat) throws FileNotFoundException { super(new FileOutputStream(new File( new StringBuilder(reportOut) .append(File.separator) - .append(REPORT_NAME) + .append(reportName) .append(".") .append(reportFormat.name()) .toString())), diff --git a/src/main/resources/version b/src/main/resources/version index 033a30f..458a4e0 100644 --- a/src/main/resources/version +++ b/src/main/resources/version @@ -1 +1 @@ -Version: 1.1.4 \ No newline at end of file +Version: 1.2.2 \ No newline at end of file From 6434f6dca68329434f514e6957ceef68e30b52a1 Mon Sep 17 00:00:00 2001 From: Mikhail Rusakovich Date: Sun, 3 Jul 2022 21:46:00 +0300 Subject: [PATCH 10/12] mitigationsPath clear in case if mitigations file not found in mitPath folder. v1.2.3 --- pom.xml | 4 ++-- src/main/java/com/github/rusakovichma/tictaac/Launcher.java | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 16430cc..a17168a 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.github.rusakovichma tictaac - 1.2.2 + 1.2.3 TicTaaC https://github.com/rusakovichma/TicTaaC.git @@ -30,7 +30,7 @@ scm:git:https://github.com/rusakovichma/TicTaaC.git https://github.com/rusakovichma/TicTaaC scm:git:https://github.com/rusakovichma/TicTaaC.git - v1.2.2 + v1.2.3 github diff --git a/src/main/java/com/github/rusakovichma/tictaac/Launcher.java b/src/main/java/com/github/rusakovichma/tictaac/Launcher.java index 7e4b051..22cfaa3 100644 --- a/src/main/java/com/github/rusakovichma/tictaac/Launcher.java +++ b/src/main/java/com/github/rusakovichma/tictaac/Launcher.java @@ -89,6 +89,8 @@ private static Mitigator getMitigator(Map params) { mitigationsFile.getAbsolutePath() + File.separator + threatModelName + "-mitigations.yml"); if (threatModelMitigationsFile.exists()) { mitigationsPath = threatModelMitigationsFile.getAbsolutePath(); + } else { + mitigationsPath = null; } } } From cb41953b9ada8a200dc0fe3248d79748c2d4d94c Mon Sep 17 00:00:00 2001 From: Mikhail Rusakovich Date: Sun, 3 Jul 2022 21:52:08 +0300 Subject: [PATCH 11/12] v1.2.3 --- src/main/resources/version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/version b/src/main/resources/version index 458a4e0..e56cace 100644 --- a/src/main/resources/version +++ b/src/main/resources/version @@ -1 +1 @@ -Version: 1.2.2 \ No newline at end of file +Version: 1.2.3 \ No newline at end of file From 9957dc1d9eb863505330788d985451bf7adb44a2 Mon Sep 17 00:00:00 2001 From: Mikhail Rusakovich Date: Sun, 3 Jul 2022 22:10:48 +0300 Subject: [PATCH 12/12] release notes and readme update --- README.md | 20 ++++++++++++++------ RELEASE_NOTES.md | 9 ++++++++- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 4162d3c..a312715 100644 --- a/README.md +++ b/README.md @@ -22,19 +22,26 @@ All the tool is needed is a data flow code file described in th More detailed instructions can be found on the [github wiki](https://github.com/rusakovichma/TicTaaC/wiki). The latest CLI can be downloaded from github in the [releases section](https://github.com/rusakovichma/TicTaaC/releases).
-On *nix +On *nix: ``` $ ./bin/tic-taac.sh -h -$ ./bin/tic-taac.sh --out . --threatModel [path to threat model file] +$ ./bin/tic-taac.sh --out . --threatModel [path to threat model file(s) or folder to scan] ``` -On Windows +On Windows: ``` > .\bin\tic-taac.bat -h -> .\bin\tic-taac.bat --out . --threatModel [path to threat model file] +> .\bin\tic-taac.bat --out . --threatModel [path to threat model file(s) or folder to scan] ``` ### Docker See [TicTaaC Docker Hub repository](https://hub.docker.com/r/rusakovichma/tic-taac). + +Quickstart on Windows: +``` +> docker run --volume /D/threat-model:/threat-model --volume /D/report:/report rusakovichma/tic-taac:latest --threatModel /threat-model/ --out /report +``` + +*nix script: ```console #!/bin/sh @@ -50,12 +57,13 @@ docker run --rm \ --volume $THREAT_MODEL_DIR:/threat-model:z \ --volume $(pwd)/report:/report:z \ rusakovichma/tic-taac:$TT_VERSION \ - --threatModel /threat-model/simpest-threat-model.yml \ + --threatModel /threat-model \ --outFormat html \ --out /report # Set mitigation strategy for the corresponding threats # see https://github.com/rusakovichma/TicTaaC/blob/master/expl/mitigations.yml - # --mitigations /threat-model/mitigations.yml + # --mitigations /threat-model/mitigations.yml + # or set the folder where scan the mitigations files: --mitigations /mitigations ``` ### Jenkins pipeline For TicTaaC usage at Jenkins pipeline, see [Jenkinsfile example](https://github.com/rusakovichma/TicTaaC/blob/master/cicd/Jenkinsfile). diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index abf7bde..7f899c3 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1 +1,8 @@ -# Release Notes \ No newline at end of file +# Release Notes + +## [Version 1.2.3](https://github.com/jeremylong/DependencyCheck/releases/tag/v7.1.1) (2022-07-03) + +**Changes** + +- Bug fixes. +- Multiple Threat Modeling files support and files scan ([see #1](https://github.com/rusakovichma/TicTaaC/issues/1)). \ No newline at end of file