From cf01342d74dd1195acbab8dd015ce83ee976098f Mon Sep 17 00:00:00 2001 From: To-om Date: Fri, 29 Oct 2021 13:15:47 +0200 Subject: [PATCH 1/4] #387 Add cortex container settings --- .../cortex/services/DockerJobRunnerSrv.scala | 37 +++++++++++++------ 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/app/org/thp/cortex/services/DockerJobRunnerSrv.scala b/app/org/thp/cortex/services/DockerJobRunnerSrv.scala index 5931cac12..b92d1dfe6 100644 --- a/app/org/thp/cortex/services/DockerJobRunnerSrv.scala +++ b/app/org/thp/cortex/services/DockerJobRunnerSrv.scala @@ -23,6 +23,7 @@ import org.elastic4play.utils.RichFuture @Singleton class DockerJobRunnerSrv( client: DockerClient, + config: Configuration, autoUpdate: Boolean, jobBaseDirectory: Path, dockerJobBaseDirectory: Path, @@ -42,6 +43,7 @@ class DockerJobRunnerSrv( .uri(config.getOptional[String]("docker.uri").getOrElse("unix:///var/run/docker.sock")) .useProxy(config.getOptional[Boolean]("docker.useProxy").getOrElse(false)) .build(), + config, config.getOptional[Boolean]("docker.autoUpdate").getOrElse(true), Paths.get(config.get[String]("job.directory")), Paths.get(config.get[String]("job.dockerDirectory")), @@ -64,20 +66,33 @@ class DockerJobRunnerSrv( import scala.collection.JavaConverters._ if (autoUpdate) client.pull(dockerImage) // ContainerConfig.builder().addVolume() - val hostConfig = HostConfig - .builder() - .appendBinds( - Bind - .from(dockerJobBaseDirectory.resolve(jobBaseDirectory.relativize(jobDirectory)).toAbsolutePath.toString) - .to("/job") - .readOnly(false) - .build() - ) - .build() + val hostConfigBuilder = HostConfig.builder() + config.getOptional[Seq[String]]("docker.container.capAdd").map(_.asJava).foreach(hostConfigBuilder.capAdd) + config.getOptional[Seq[String]]("docker.container.capDrop").map(_.asJava).foreach(hostConfigBuilder.capDrop) + config.getOptional[String]("docker.container.cgroupParent").foreach(hostConfigBuilder.cgroupParent) + config.getOptional[Long]("docker.container.cpuPeriod").foreach(hostConfigBuilder.cpuPeriod(_)) + config.getOptional[Long]("docker.container.cpuQuota").foreach(hostConfigBuilder.cpuQuota(_)) + config.getOptional[Seq[String]]("docker.container.dns").map(_.asJava).foreach(hostConfigBuilder.dns) + config.getOptional[Seq[String]]("docker.container.dnsSearch").map(_.asJava).foreach(hostConfigBuilder.dnsSearch) + config.getOptional[Seq[String]]("docker.container.extraHosts").map(_.asJava).foreach(hostConfigBuilder.extraHosts) + config.getOptional[Long]("docker.container.kernelMemory").foreach(hostConfigBuilder.kernelMemory(_)) + config.getOptional[Long]("docker.container.memoryReservation").foreach(hostConfigBuilder.memoryReservation(_)) + config.getOptional[Long]("docker.container.memory").foreach(hostConfigBuilder.memory(_)) + config.getOptional[Long]("docker.container.memorySwap").foreach(hostConfigBuilder.memorySwap(_)) + config.getOptional[Int]("docker.container.memorySwappiness").foreach(hostConfigBuilder.memorySwappiness(_)) + config.getOptional[String]("docker.container.networkMode").foreach(hostConfigBuilder.networkMode) + config.getOptional[Boolean]("docker.container.privileged").foreach(hostConfigBuilder.privileged(_)) + hostConfigBuilder.appendBinds( + Bind + .from(dockerJobBaseDirectory.resolve(jobBaseDirectory.relativize(jobDirectory)).toAbsolutePath.toString) + .to("/job") + .readOnly(false) + .build() + ) val cacertsFile = jobDirectory.resolve("input").resolve("cacerts") val containerConfigBuilder = ContainerConfig .builder() - .hostConfig(hostConfig) + .hostConfig(hostConfigBuilder.build()) .image(dockerImage) .cmd("/job") From 279a152fb32ccb11f8e953aa8f91285b261763d4 Mon Sep 17 00:00:00 2001 From: To-om Date: Fri, 29 Oct 2021 16:19:38 +0200 Subject: [PATCH 2/4] Update elastic4play --- project/Dependencies.scala | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index c221cd023..c56ee6473 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -5,21 +5,21 @@ object Dependencies { object Play { val version = play.core.PlayVersion.current - val ws = "com.typesafe.play" %% "play-ws" % version - val ahc = "com.typesafe.play" %% "play-ahc-ws" % version - val cache = "com.typesafe.play" %% "play-ehcache" % version - val test = "com.typesafe.play" %% "play-test" % version - val specs2 = "com.typesafe.play" %% "play-specs2" % version + val ws = "com.typesafe.play" %% "play-ws" % version + val ahc = "com.typesafe.play" %% "play-ahc-ws" % version + val cache = "com.typesafe.play" %% "play-ehcache" % version + val test = "com.typesafe.play" %% "play-test" % version + val specs2 = "com.typesafe.play" %% "play-specs2" % version val filters = "com.typesafe.play" %% "filters-helpers" % version - val guice = "com.typesafe.play" %% "play-guice" % version + val guice = "com.typesafe.play" %% "play-guice" % version } val scalaGuice = "net.codingwell" %% "scala-guice" % "4.1.0" - val reflections = "org.reflections" % "reflections" % "0.9.11" - val zip4j = "net.lingala.zip4j" % "zip4j" % "1.3.2" - val elastic4play = "org.thehive-project" %% "elastic4play" % "1.13.1" - val dockerClient = "com.spotify" % "docker-client" % "8.14.4" + val reflections = "org.reflections" % "reflections" % "0.9.11" + val zip4j = "net.lingala.zip4j" % "zip4j" % "1.3.2" + val elastic4play = "org.thehive-project" %% "elastic4play" % "1.13.2" + val dockerClient = "com.spotify" % "docker-client" % "8.14.4" val akkaCluster = "com.typesafe.akka" %% "akka-cluster" % play.core.PlayVersion.akkaVersion val akkaClusterTyped = "com.typesafe.akka" %% "akka-cluster-typed" % play.core.PlayVersion.akkaVersion } From 30658e2f8fa7b57a8cf14dfe66000fc88c21341d Mon Sep 17 00:00:00 2001 From: To-om Date: Thu, 4 Nov 2021 17:36:43 +0100 Subject: [PATCH 3/4] #388 Add docker image with deps --- .drone.yml | 18 ++++- build.sbt | 74 ++++++++++-------- debian.sbt | 21 ------ docker.sbt | 62 --------------- package.sbt | 55 -------------- project/Common.scala | 3 +- project/DockerSettings.scala | 120 +++++++++++++++++++++++++++++ project/PackageSettings.scala | 138 ++++++++++++++++++++++++++++++++++ project/build.properties | 2 +- rpm.sbt | 51 ------------- version.sbt | 2 +- 11 files changed, 322 insertions(+), 224 deletions(-) delete mode 100644 debian.sbt delete mode 100644 docker.sbt delete mode 100644 package.sbt create mode 100644 project/DockerSettings.scala create mode 100644 project/PackageSettings.scala delete mode 100644 rpm.sbt diff --git a/.drone.yml b/.drone.yml index c19dcdc05..9697d6ca9 100644 --- a/.drone.yml +++ b/.drone.yml @@ -36,7 +36,7 @@ steps: fi . ~/.nvm/nvm.sh [ -n "$PLUGIN_PGP_KEY" ] && gpg --batch --import - <<< $PLUGIN_PGP_KEY - sbt -Duser.home=$PWD docker:stage debian:packageBin rpm:packageBin universal:packageBin + sbt -Duser.home=$PWD Docker/stage Debian/packageBin Rpm/packageBin Universal/packageBin cortexWithDeps/Docker/stage if ( echo $V | grep -qi rc ) then echo $( echo $V | sed -re 's/([0-9]+.[0-9]+.[0-9]+)-RC([0-9]+)-([0-9]+)/\1-RC\2,\1-RC\2-\3/' ) > .tags @@ -104,6 +104,22 @@ steps: when: event: [tag] + - name: update docker tags + image: thehiveproject/drone-scala-node + commands: sed -i -e 's/,/-withdeps,/g; s/$/-withdeps/' .tags + + # Publish docker image on Docker Hub + - name: docker + image: plugins/docker + settings: + context: target/docker-withdeps/target/docker/stage + dockerfile: target/docker-withdeps/target/docker/stage/Dockerfile + repo: thehiveproject/cortex + username: {from_secret: docker_username} + password: {from_secret: docker_password} + when: + event: [tag] + # Publish docker image on Harbor - name: harbor image: plugins/docker diff --git a/build.sbt b/build.sbt index f25d5d42d..cbc06ead0 100644 --- a/build.sbt +++ b/build.sbt @@ -3,34 +3,48 @@ import Common._ lazy val cortex = (project in file(".")) .enablePlugins(PlayScala) .settings(projectSettings) + .settings(PackageSettings.packageSettings) + .settings(PackageSettings.rpmSettings) + .settings(PackageSettings.debianSettings) + .settings(DockerSettings.default) + .settings( + Seq( + libraryDependencies ++= Seq( + Dependencies.Play.cache, + Dependencies.Play.ws, + Dependencies.Play.ahc, + Dependencies.Play.specs2 % Test, + Dependencies.Play.guice, + Dependencies.scalaGuice, + Dependencies.elastic4play, + Dependencies.reflections, + Dependencies.zip4j, + Dependencies.dockerClient, + Dependencies.akkaCluster, + Dependencies.akkaClusterTyped + ), + resolvers += Resolver.sbtPluginRepo("releases"), + resolvers += "scalaz-bintray" at "https://dl.bintray.com/scalaz/releases", + resolvers += "elasticsearch-releases" at "https://artifacts.elastic.co/maven", + Compile / packageDoc / publishArtifact := false, + Compile / doc / sources := Seq.empty, + // Front-end // + Assets / packageBin / mappings ++= frontendFiles.value, + packageBin := { + (Debian / packageBin).value + (Rpm / packageBin).value + (Universal / packageBin).value + } + ) + ) -libraryDependencies ++= Seq( - Dependencies.Play.cache, - Dependencies.Play.ws, - Dependencies.Play.ahc, - Dependencies.Play.specs2 % Test, - Dependencies.Play.guice, - Dependencies.scalaGuice, - Dependencies.elastic4play, - Dependencies.reflections, - Dependencies.zip4j, - Dependencies.dockerClient, - Dependencies.akkaCluster, - Dependencies.akkaClusterTyped -) - -resolvers += Resolver.sbtPluginRepo("releases") -resolvers += "scalaz-bintray" at "https://dl.bintray.com/scalaz/releases" -resolvers += "elasticsearch-releases" at "https://artifacts.elastic.co/maven" -publishArtifact in (Compile, packageDoc) := false -publishArtifact in packageDoc := false -sources in (Compile, doc) := Seq.empty - -// Front-end // -mappings in packageBin in Assets ++= frontendFiles.value - -packageBin := { - (packageBin in Debian).value - (packageBin in Rpm).value - (packageBin in Universal).value -} +lazy val cortexWithDeps = (project in file("target/docker-withdeps")) + .dependsOn(cortex) + .enablePlugins(DockerPlugin) + .settings(projectSettings) + .settings(DockerSettings.withDeps) + .settings( + Docker / mappings := (cortex / Docker / mappings).value, + Docker / version := version.value + "-withdeps", + Docker / packageName := "cortex" + ) diff --git a/debian.sbt b/debian.sbt deleted file mode 100644 index f9d804d14..000000000 --- a/debian.sbt +++ /dev/null @@ -1,21 +0,0 @@ -import Common.{betaVersion, snapshotVersion, stableVersion, versionUsage} - -linuxPackageMappings in Debian += packageMapping(file("LICENSE") -> "/usr/share/doc/cortex/copyright").withPerms("644") -version in Debian := { - version.value match { - case stableVersion(_, _) => version.value - case betaVersion(v1, v2, v3) => v1 + "-0." + v3 + "RC" + v2 - case snapshotVersion(stableVersion(v1, v2)) => v1 + "-" + v2 + "-SNAPSHOT" - case snapshotVersion(betaVersion(v1, v2, v3)) => v1 + "-0." + v3 + "RC" + v2 + "-SNAPSHOT" - case _ => versionUsage(version.value) - } -} - -debianPackageRecommends := Seq("elasticsearch") -debianPackageDependencies += "java8-runtime | java8-runtime-headless" -maintainerScripts in Debian := maintainerScriptsFromDirectory( - baseDirectory.value / "package" / "debian", - Seq(DebianConstants.Postinst, DebianConstants.Prerm, DebianConstants.Postrm) -) -linuxEtcDefaultTemplate in Debian := (baseDirectory.value / "package" / "etc_default_cortex").asURL -linuxMakeStartScript in Debian := None diff --git a/docker.sbt b/docker.sbt deleted file mode 100644 index b00495861..000000000 --- a/docker.sbt +++ /dev/null @@ -1,62 +0,0 @@ -import Common.{betaVersion, snapshotVersion, stableVersion, versionUsage} -import com.typesafe.sbt.packager.docker.{Cmd, ExecCmd} - -version in Docker := { - version.value match { - case stableVersion(_, _) => version.value - case betaVersion(v1, v2, v3) => v1 + "-0." + v3 + "RC" + v2 - case snapshotVersion(stableVersion(v1, v2)) => v1 + "-" + v2 + "-SNAPSHOT" - case snapshotVersion(betaVersion(v1, v2, v3)) => v1 + "-0." + v3 + "RC" + v2 + "-SNAPSHOT" - case _ => versionUsage(version.value) - } -} -defaultLinuxInstallLocation in Docker := "/opt/cortex" -dockerRepository := Some("thehiveproject") -dockerUpdateLatest := !version.value.toUpperCase.contains("RC") && !version.value.contains("SNAPSHOT") -dockerEntrypoint := Seq("/opt/cortex/entrypoint") -dockerExposedPorts := Seq(9001) -mappings in Docker ++= Seq( - file("package/docker/entrypoint") -> "/opt/cortex/entrypoint", - file("package/logback.xml") -> "/etc/cortex/logback.xml", - file("package/empty") -> "/var/log/cortex/application.log" -) -mappings in Docker ~= (_.filterNot { - case (_, filepath) => filepath == "/opt/cortex/conf/application.conf" -}) -dockerCommands := Seq( - Cmd("FROM", "openjdk:8"), - Cmd("LABEL", "MAINTAINER=\"TheHive Project \"", "repository=\"https://github.com/TheHive-Project/TheHive\""), - Cmd("WORKDIR", "/opt/cortex"), - // format: off - Cmd("RUN", - "wget", "-q", "-O", "-", "https://download.docker.com/linux/static/stable/x86_64/docker-18.09.0.tgz", "|", - "tar", "-xzC", "/usr/local/bin/", "--strip-components", "1", "&&", - "addgroup", "--system", "dockremap", "&&", - "adduser", "--system", "--ingroup", "dockremap", "dockremap", "&&", - "addgroup", "--system", "docker", "&&", - "echo", "dockremap:165536:65536", ">>", "/etc/subuid", "&&", - "echo", "dockremap:165536:65536", ">>", "/etc/subgid", "&&", - "apt", "update", "&&", - "apt", "upgrade", "-y", "&&", - "apt", "install", "-y", "iptables", "lxc", "&&", - "apt", "autoclean", "-y", "-q", "&&", - "apt", "autoremove", "-y", "-q", "&&", - "rm", "-rf", "/var/lib/apt/lists/*", "&&", - "(", "type", "groupadd", "1>/dev/null", "2>&1", "&&", - "groupadd", "-g", "1001", "cortex", "||", - "addgroup", "-g", "1001", "-S", "cortex", - ")", "&&", - "(", "type", "useradd", "1>/dev/null", "2>&1", "&&", - "useradd", "--system", "--uid", "1001", "--gid", "1001", "cortex", "||", - "adduser", "-S", "-u", "1001", "-G", "cortex", "cortex", - ")"), - //format: on - Cmd("ADD", "--chown=root:root", "opt", "/opt"), - Cmd("ADD", "--chown=cortex:cortex", "var", "/var"), - Cmd("ADD", "--chown=cortex:cortex", "etc", "/etc"), - Cmd("VOLUME", "/var/lib/docker"), - ExecCmd("RUN", "chmod", "+x", "/opt/cortex/bin/cortex", "/opt/cortex/entrypoint"), - Cmd("EXPOSE", "9001"), - ExecCmd("ENTRYPOINT", "/opt/cortex/entrypoint"), - ExecCmd("CMD") -) diff --git a/package.sbt b/package.sbt deleted file mode 100644 index 5ca968275..000000000 --- a/package.sbt +++ /dev/null @@ -1,55 +0,0 @@ -// Add information in manifest -import Package.ManifestAttributes -import java.util.jar.Attributes.Name._ -packageOptions ++= Seq( - ManifestAttributes(IMPLEMENTATION_TITLE -> name.value), - ManifestAttributes(IMPLEMENTATION_VERSION -> version.value), - ManifestAttributes(SPECIFICATION_VENDOR -> "TheHive Project"), - ManifestAttributes(SPECIFICATION_TITLE -> name.value), - ManifestAttributes(SPECIFICATION_VERSION -> "TheHive Project") -) - -// Install files // -mappings in Universal ~= { - _.flatMap { - case (_, "conf/application.conf") => Nil - case (file, "conf/apllication.sample") => Seq(file -> "conf/application.conf") - case (_, "conf/logback.xml") => Nil - case other => Seq(other) - } ++ Seq( - file("package/cortex.service") -> "package/cortex.service", - file("package/cortex.conf") -> "package/cortex.conf", - file("package/cortex") -> "package/cortex", - file("package/logback.xml") -> "conf/logback.xml" - ) -} - -maintainer := "TheHive Project " -packageSummary := "Powerful Observable Analysis Engine" -packageDescription := """Cortex tries to solve a common problem frequently encountered by SOCs, CSIRTs and security - | researchers in the course of threat intelligence, digital forensics and incident response: how to analyze - | observables they have collected, at scale, by querying a single tool instead of several? - | Cortex, an open source and free software, has been created by TheHive Project for this very purpose. Observables, - | such as IP and email addresses, URLs, domain names, files or hashes, can be analyzed one by one or in bulk mode - | using a Web interface. Analysts can also automate these operations thanks to the Cortex REST API. """.stripMargin -defaultLinuxInstallLocation := "/opt" -linuxPackageMappings ~= { - _.map { pm => - val mappings = pm.mappings.filterNot { - case (_, path) => path.startsWith("/opt/cortex/package") || (path.startsWith("/opt/cortex/conf") && path != "/opt/cortex/conf/reference.conf") - } - com.typesafe.sbt.packager.linux.LinuxPackageMapping(mappings, pm.fileData).withConfig() - } :+ packageMapping( - file("package/cortex.service") -> "/etc/systemd/system/cortex.service", - file("package/cortex.conf") -> "/etc/init/cortex.conf", - file("package/cortex") -> "/etc/init.d/cortex", - file("conf/application.sample") -> "/etc/cortex/application.conf", - file("package/logback.xml") -> "/etc/cortex/logback.xml" - ).withConfig() -} - -packageBin := { - (packageBin in Debian).value - (packageBin in Rpm).value - (packageBin in Universal).value -} diff --git a/project/Common.scala b/project/Common.scala index 4cf047169..4a61bdbde 100644 --- a/project/Common.scala +++ b/project/Common.scala @@ -10,7 +10,6 @@ object Common { organization := "org.thehive-project", licenses += "AGPL-V3" -> url("https://www.gnu.org/licenses/agpl-3.0.html"), organizationHomepage := Some(url("http://thehive-project.org/")), - resolvers += Resolver.bintrayRepo("thehive-project", "maven"), resolvers += "elasticsearch-releases" at "https://artifacts.elastic.co/maven", scalaVersion := Dependencies.scalaVersion, scalacOptions ++= Seq( @@ -34,7 +33,7 @@ object Common { // Redirect logs from ElasticSearch (which uses log4j2) to slf4j libraryDependencies += "org.apache.logging.log4j" % "log4j-to-slf4j" % "2.9.1", excludeDependencies += "org.apache.logging.log4j" % "log4j-core", - dependencyOverrides += "com.typesafe.akka" %% "akka-actor" % play.core.PlayVersion.akkaVersion + dependencyOverrides += "com.typesafe.akka" %% "akka-actor" % play.core.PlayVersion.akkaVersion ) val stableVersion: Regex = "(\\d+\\.\\d+\\.\\d+)-(\\d+)".r diff --git a/project/DockerSettings.scala b/project/DockerSettings.scala new file mode 100644 index 000000000..ebb1b7eb3 --- /dev/null +++ b/project/DockerSettings.scala @@ -0,0 +1,120 @@ +import Common.{betaVersion, snapshotVersion, stableVersion, versionUsage} +import com.typesafe.sbt.packager.docker.DockerPlugin.autoImport._ +import com.typesafe.sbt.packager.docker.{Cmd, ExecCmd} +import com.typesafe.sbt.packager.linux.LinuxPlugin.autoImport.defaultLinuxInstallLocation +import sbt.Keys._ +import sbt._ + +object DockerSettings { + val default = Seq( + Docker / version := { + version.value match { + case stableVersion(_, _) => version.value + case betaVersion(v1, v2, v3) => v1 + "-0." + v3 + "RC" + v2 + case snapshotVersion(stableVersion(v1, v2)) => v1 + "-" + v2 + "-SNAPSHOT" + case snapshotVersion(betaVersion(v1, v2, v3)) => v1 + "-0." + v3 + "RC" + v2 + "-SNAPSHOT" + case _ => versionUsage(version.value) + } + }, + Docker / defaultLinuxInstallLocation := "/opt/cortex", + dockerRepository := Some("thehiveproject"), + dockerUpdateLatest := !version.value.toUpperCase.contains("RC") && !version.value.contains("SNAPSHOT"), + dockerExposedPorts := Seq(9001), + Docker / mappings ++= Seq( + file("package/docker/entrypoint") -> "/opt/cortex/entrypoint", + file("package/logback.xml") -> "/etc/cortex/logback.xml", + file("package/empty") -> "/var/log/cortex/application.log" + ), + Docker / mappings ~= (_.filterNot { + case (_, filepath) => filepath == "/opt/cortex/conf/application.conf" + }), + dockerCommands := Seq( + Cmd("FROM", "openjdk:8"), + Cmd("LABEL", "MAINTAINER=\"TheHive Project \"", "repository=\"https://github.com/TheHive-Project/TheHive\""), + Cmd("WORKDIR", "/opt/cortex"), + // format: off + Cmd("RUN", + "wget", "-q", "-O", "-", "https://download.docker.com/linux/static/stable/x86_64/docker-18.09.0.tgz", "|", + "tar", "-xzC", "/usr/local/bin/", "--strip-components", "1", "&&", + "addgroup", "--system", "dockremap", "&&", + "adduser", "--system", "--ingroup", "dockremap", "dockremap", "&&", + "addgroup", "--system", "docker", "&&", + "echo", "dockremap:165536:65536", ">>", "/etc/subuid", "&&", + "echo", "dockremap:165536:65536", ">>", "/etc/subgid", "&&", + "apt", "update", "&&", + "apt", "upgrade", "-y", "&&", + "apt", "install", "-y", "iptables", "lxc", "&&", + "apt", "autoclean", "-y", "-q", "&&", + "apt", "autoremove", "-y", "-q", "&&", + "rm", "-rf", "/var/lib/apt/lists/*", "&&", + "(", "type", "groupadd", "1>/dev/null", "2>&1", "&&", + "groupadd", "-g", "1001", "cortex", "||", + "addgroup", "-g", "1001", "-S", "cortex", + ")", "&&", + "(", "type", "useradd", "1>/dev/null", "2>&1", "&&", + "useradd", "--system", "--uid", "1001", "--gid", "1001", "cortex", "||", + "adduser", "-S", "-u", "1001", "-G", "cortex", "cortex", + ")"), + //format: on + Cmd("ADD", "--chown=root:root", "opt", "/opt"), + Cmd("ADD", "--chown=cortex:cortex", "var", "/var"), + Cmd("ADD", "--chown=cortex:cortex", "etc", "/etc"), + Cmd("VOLUME", "/var/lib/docker"), + ExecCmd("RUN", "chmod", "+x", "/opt/cortex/bin/cortex", "/opt/cortex/entrypoint"), + Cmd("EXPOSE", "9001"), + ExecCmd("ENTRYPOINT", "/opt/cortex/entrypoint"), + ExecCmd("CMD") + ) + ) + + val withDeps = default ++ Seq( + dockerCommands ++= Seq( + Cmd( + "RUN", + """ + | apt update && + | apt upgrade -y && + | apt install -y -q --no-install-recommends --no-install-suggests + | wkhtmltopdf libfuzzy-dev libimage-exiftool-perl + | libboost-regex-dev + | libboost-program-options-dev + | libboost-system-dev libboost-filesystem-dev libssl-dev + | build-essential cmake python3-dev python2-dev + | git python3 python3-pip libffi-dev libjpeg62-turbo-dev libtiff5-dev + | libopenjp2-7-dev zlib1g-dev libfreetype6-dev liblcms2-dev libwebp-dev + | tcl8.6-dev tk8.6-dev python3-tk libharfbuzz-dev libfribidi-dev + | libxcb1-dev python2.7 && + | rm -rf /var/lib/apt/lists/* && + | curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output /tmp/get-pip.py && + | python2.7 /tmp/get-pip.py && + | pip2 install -U setuptools && + | pip3 install -U setuptools && + | ln -sf python3 /usr/bin/python && + | hash -r && + | git clone https://github.com/JusticeRage/Manalyze.git /tmp/Manalyze && + | cd /tmp/Manalyze && + | cmake . && + | make -j5 && + | cd /tmp/Manalyze/bin/yara_rules && + | pip3 install requests && + | python3 update_clamav_signatures.py && + | cd /tmp/Manalyze && + | make install && + | cd / && + | rm -rf /tmp/Manalyze && + | curl -SL https://github.com/fireeye/flare-floss/releases/download/v1.7.0/floss-v1.7.0-linux.zip + | --output /tmp/floss.zip && + | unzip /tmp/floss.zip -d /usr/bin && + | rm /tmp/floss.zip && + | git clone https://github.com/TheHive-Project/Cortex-Analyzers.git /tmp/analyzers && + | cat $(find /tmp/analyzers -name requirements.txt) | sort -u | while read I ; + | do + | pip2 install $I || true && + | pip3 install $I || true ; + | done && + | rm -rf /tmp/analyzers + """.stripMargin.split("\\s").filter(_.nonEmpty): _* + ) + ) + ) +} diff --git a/project/PackageSettings.scala b/project/PackageSettings.scala new file mode 100644 index 000000000..a2ed84973 --- /dev/null +++ b/project/PackageSettings.scala @@ -0,0 +1,138 @@ +import Common.{betaVersion, snapshotVersion, stableVersion, versionUsage} +import com.typesafe.sbt.SbtNativePackager.autoImport.{maintainer, maintainerScripts, packageDescription, packageSummary} +import com.typesafe.sbt.packager.Keys._ +import com.typesafe.sbt.packager.archetypes.JavaAppPackaging.autoImport.maintainerScriptsFromDirectory +import com.typesafe.sbt.packager.debian.DebianPlugin.autoImport.{debianPackageDependencies, debianPackageRecommends, Debian, DebianConstants} +import com.typesafe.sbt.packager.linux.LinuxPlugin.autoImport.{ + defaultLinuxInstallLocation, + linuxEtcDefaultTemplate, + linuxMakeStartScript, + linuxPackageMappings, + packageMapping +} +import com.typesafe.sbt.packager.linux.Mapper.configWithNoReplace +import com.typesafe.sbt.packager.rpm.RpmPlugin.autoImport.{Rpm, RpmConstants} +import com.typesafe.sbt.packager.universal.UniversalPlugin.autoImport.Universal +import sbt.Keys._ +import sbt.Package.ManifestAttributes +import sbt._ + +import java.util.jar.Attributes.Name._ + +object PackageSettings { + val rpmSettings = Seq( + Rpm / version := { + version.value match { + case stableVersion(v1, _) => v1 + case betaVersion(v1, _, _) => v1 + case snapshotVersion(stableVersion(v1, _)) => v1 + case snapshotVersion(betaVersion(v1, _, _)) => v1 + case _ => versionUsage(version.value) + } + }, + rpmRelease := { + version.value match { + case stableVersion(_, v2) => v2 + case betaVersion(_, v2, v3) => "0." + v3 + "RC" + v2 + case snapshotVersion(stableVersion(_, v2)) => v2 + "-SNAPSHOT" + case snapshotVersion(betaVersion(_, v2, v3)) => "0." + v3 + "RC" + v2 + "-SNAPSHOT" + case _ => versionUsage(version.value) + } + }, + rpmVendor := organizationName.value, + rpmUrl := organizationHomepage.value.map(_.toString), + rpmLicense := Some("AGPL"), + rpmRequirements += "java-1.8.0-openjdk-headless", + Rpm / maintainerScripts := maintainerScriptsFromDirectory( + baseDirectory.value / "package" / "rpm", + Seq(RpmConstants.Pre, RpmConstants.Preun, RpmConstants.Post, RpmConstants.Postun) + ), + Rpm / linuxPackageSymlinks := Nil, + rpmPrefix := Some(defaultLinuxInstallLocation.value), + Rpm / linuxEtcDefaultTemplate := (baseDirectory.value / "package" / "etc_default_cortex").asURL, + Rpm / linuxPackageMappings := configWithNoReplace((Rpm / linuxPackageMappings).value), + Rpm / packageBin := { + import scala.sys.process._ + val rpmFile = (Rpm / packageBin).value + Process( + "rpm" :: + "--define" :: "_gpg_name TheHive Project" :: + "--define" :: "_signature gpg" :: + "--define" :: "__gpg_check_password_cmd /bin/true" :: + "--define" :: "__gpg_sign_cmd %{__gpg} gpg --batch --no-verbose --no-armor --use-agent --no-secmem-warning -u \"%{_gpg_name}\" -sbo %{__signature_filename} %{__plaintext_filename}" :: + "--addsign" :: rpmFile.toString :: + Nil + ).!! + rpmFile + } + ) + + val debianSettings = Seq( + Debian / linuxPackageMappings += packageMapping(file("LICENSE") -> "/usr/share/doc/cortex/copyright").withPerms("644"), + Debian / version := { + version.value match { + case stableVersion(_, _) => version.value + case betaVersion(v1, v2, v3) => v1 + "-0." + v3 + "RC" + v2 + case snapshotVersion(stableVersion(v1, v2)) => v1 + "-" + v2 + "-SNAPSHOT" + case snapshotVersion(betaVersion(v1, v2, v3)) => v1 + "-0." + v3 + "RC" + v2 + "-SNAPSHOT" + case _ => versionUsage(version.value) + } + }, + debianPackageRecommends := Seq("elasticsearch"), + debianPackageDependencies += "java8-runtime | java8-runtime-headless", + Debian / maintainerScripts := maintainerScriptsFromDirectory( + baseDirectory.value / "package" / "debian", + Seq(DebianConstants.Postinst, DebianConstants.Prerm, DebianConstants.Postrm) + ), + Debian / linuxEtcDefaultTemplate := (baseDirectory.value / "package" / "etc_default_cortex").asURL, + Debian / linuxMakeStartScript := None + ) + + val packageSettings = Seq( + packageOptions ++= Seq( + ManifestAttributes(IMPLEMENTATION_TITLE -> name.value), + ManifestAttributes(IMPLEMENTATION_VERSION -> version.value), + ManifestAttributes(SPECIFICATION_VENDOR -> "TheHive Project"), + ManifestAttributes(SPECIFICATION_TITLE -> name.value), + ManifestAttributes(SPECIFICATION_VERSION -> "TheHive Project") + ), + // Install files // + Universal / mappings ~= { + _.flatMap { + case (_, "conf/application.conf") => Nil + case (file, "conf/apllication.sample") => Seq(file -> "conf/application.conf") + case (_, "conf/logback.xml") => Nil + case other => Seq(other) + } ++ Seq( + file("package/cortex.service") -> "package/cortex.service", + file("package/cortex.conf") -> "package/cortex.conf", + file("package/cortex") -> "package/cortex", + file("package/logback.xml") -> "conf/logback.xml" + ) + }, + maintainer := "TheHive Project ", + packageSummary := "Powerful Observable Analysis Engine", + packageDescription := """Cortex tries to solve a common problem frequently encountered by SOCs, CSIRTs and security + | researchers in the course of threat intelligence, digital forensics and incident response: how to analyze + | observables they have collected, at scale, by querying a single tool instead of several? + | Cortex, an open source and free software, has been created by TheHive Project for this very purpose. Observables, + | such as IP and email addresses, URLs, domain names, files or hashes, can be analyzed one by one or in bulk mode + | using a Web interface. Analysts can also automate these operations thanks to the Cortex REST API. """.stripMargin, + defaultLinuxInstallLocation := "/opt", + linuxPackageMappings ~= { + _.map { pm => + val mappings = pm.mappings.filterNot { + case (_, path) => + path.startsWith("/opt/cortex/package") || (path.startsWith("/opt/cortex/conf") && path != "/opt/cortex/conf/reference.conf") + } + com.typesafe.sbt.packager.linux.LinuxPackageMapping(mappings, pm.fileData).withConfig() + } :+ packageMapping( + file("package/cortex.service") -> "/etc/systemd/system/cortex.service", + file("package/cortex.conf") -> "/etc/init/cortex.conf", + file("package/cortex") -> "/etc/init.d/cortex", + file("conf/application.sample") -> "/etc/cortex/application.conf", + file("package/logback.xml") -> "/etc/cortex/logback.xml" + ).withConfig() + } + ) +} diff --git a/project/build.properties b/project/build.properties index a919a9b5f..10fd9eee0 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.3.8 +sbt.version=1.5.5 diff --git a/rpm.sbt b/rpm.sbt deleted file mode 100644 index 3a14edc78..000000000 --- a/rpm.sbt +++ /dev/null @@ -1,51 +0,0 @@ -import Common.{betaVersion, snapshotVersion, stableVersion, versionUsage} - -version in Rpm := { - version.value match { - case stableVersion(v1, _) => v1 - case betaVersion(v1, _, _) => v1 - case snapshotVersion(stableVersion(v1, _)) => v1 - case snapshotVersion(betaVersion(v1, _, _)) => v1 - case _ => versionUsage(version.value) - } -} -rpmRelease := { - version.value match { - case stableVersion(_, v2) => v2 - case betaVersion(_, v2, v3) => "0." + v3 + "RC" + v2 - case snapshotVersion(stableVersion(_, v2)) => v2 + "-SNAPSHOT" - case snapshotVersion(betaVersion(_, v2, v3)) => "0." + v3 + "RC" + v2 + "-SNAPSHOT" - case _ => versionUsage(version.value) - } -} - -rpmVendor := organizationName.value -rpmUrl := organizationHomepage.value.map(_.toString) -rpmLicense := Some("AGPL") -rpmRequirements += "java-1.8.0-openjdk-headless" - -maintainerScripts in Rpm := maintainerScriptsFromDirectory( - baseDirectory.value / "package" / "rpm", - Seq(RpmConstants.Pre, RpmConstants.Preun, RpmConstants.Post, RpmConstants.Postun) -) - -linuxPackageSymlinks in Rpm := Nil -rpmPrefix := Some(defaultLinuxInstallLocation.value) -linuxEtcDefaultTemplate in Rpm := (baseDirectory.value / "package" / "etc_default_cortex").asURL - -linuxPackageMappings in Rpm := configWithNoReplace((linuxPackageMappings in Rpm).value) - -packageBin in Rpm := { - import scala.sys.process._ - val rpmFile = (packageBin in Rpm).value - Process( - "rpm" :: - "--define" :: "_gpg_name TheHive Project" :: - "--define" :: "_signature gpg" :: - "--define" :: "__gpg_check_password_cmd /bin/true" :: - "--define" :: "__gpg_sign_cmd %{__gpg} gpg --batch --no-verbose --no-armor --use-agent --no-secmem-warning -u \"%{_gpg_name}\" -sbo %{__signature_filename} %{__plaintext_filename}" :: - "--addsign" :: rpmFile.toString :: - Nil - ).!! - rpmFile -} diff --git a/version.sbt b/version.sbt index d7c2333b1..7b92e2c5a 100644 --- a/version.sbt +++ b/version.sbt @@ -1 +1 @@ -version in ThisBuild := "3.1.1-1" +ThisBuild / version := "3.1.1-1" From 294790a20282de6468eedfa3d957df842f68ebc1 Mon Sep 17 00:00:00 2001 From: To-om Date: Fri, 5 Nov 2021 11:42:20 +0100 Subject: [PATCH 4/4] Release 3.1.2 --- .drone.yml | 24 ++++++++--- CHANGELOG.md | 82 +++++++++++++++++++++----------------- project/Common.scala | 6 +-- project/Dependencies.scala | 2 +- version.sbt | 2 +- 5 files changed, 70 insertions(+), 46 deletions(-) diff --git a/.drone.yml b/.drone.yml index 9697d6ca9..9f69f743d 100644 --- a/.drone.yml +++ b/.drone.yml @@ -104,12 +104,26 @@ steps: when: event: [tag] + # Publish docker image on Harbor + - name: harbor + image: plugins/docker + settings: + context: target/docker/stage + dockerfile: target/docker/stage/Dockerfile + registry: {from_secret: harbor_registry} + repo: {from_secret: harbor_repo} + username: {from_secret: harbor_username} + password: {from_secret: harbor_password} + when: + event: [tag] + - name: update docker tags image: thehiveproject/drone-scala-node - commands: sed -i -e 's/,/-withdeps,/g; s/$/-withdeps/' .tags + commands: + - sed -i -e 's/,/-withdeps,/g; s/$/-withdeps/' .tags # Publish docker image on Docker Hub - - name: docker + - name: docker fat image: plugins/docker settings: context: target/docker-withdeps/target/docker/stage @@ -121,11 +135,11 @@ steps: event: [tag] # Publish docker image on Harbor - - name: harbor + - name: harbor fat image: plugins/docker settings: - context: target/docker/stage - dockerfile: target/docker/stage/Dockerfile + context: target/docker-withdeps/target/docker/stage + dockerfile: target/docker-withdeps/target/docker/stage/Dockerfile registry: {from_secret: harbor_registry} repo: {from_secret: harbor_repo} username: {from_secret: harbor_username} diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fbb5dbc6..fb2de93de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,16 +1,26 @@ # Change Log -## [3.1.1](https://github.com/TheHive-Project/Cortex/milestone/28) (2021-03-01) +## [3.1.2](https://github.com/TheHive-Project/Cortex/milestone/30) (2021-11-05) + +**Closed issues:** + +- More settings on docker containers instantiated by Cortex [\#387](https://github.com/TheHive-Project/Cortex/issues/387) **Implemented enhancements:** -- [Improvement] Create logfile after installation [\#341](https://github.com/TheHive-Project/Cortex/issues/341) +- Create a docker image with all dependencies [\#388](https://github.com/TheHive-Project/Cortex/issues/388) + +## [3.1.1](https://github.com/TheHive-Project/Cortex/milestone/28) (2021-03-01) **Fixed bugs:** - [BUG] Certificate not taken into account when running neurons with process [\#317](https://github.com/TheHive-Project/Cortex/issues/317) - [Bug] Update doesn't work on Elasticsearch 7.11 [\#346](https://github.com/TheHive-Project/Cortex/issues/346) +**Implemented enhancements:** + +- [Improvement] Create logfile after installation [\#341](https://github.com/TheHive-Project/Cortex/issues/341) + ## [3.1.0](https://github.com/TheHive-Project/Cortex/milestone/27) (2020-10-30) **Implemented enhancements:** @@ -25,14 +35,14 @@ ## [3.1.0-RC1](https://github.com/TheHive-Project/Cortex/milestone/21) (2020-08-13) -**Implemented enhancements:** - -- Support of ElasticSearch 7 [\#279](https://github.com/TheHive-Project/Cortex/issues/279) - **Fixed bugs:** - OAuth2 SSO Login Broken [\#264](https://github.com/TheHive-Project/Cortex/issues/264) +**Implemented enhancements:** + +- Support of ElasticSearch 7 [\#279](https://github.com/TheHive-Project/Cortex/issues/279) + ## [3.0.1](https://github.com/TheHive-Project/Cortex/milestone/24) (2020-04-24) **Implemented enhancements:** @@ -58,17 +68,17 @@ ## [3.0.0-RC4](https://github.com/TheHive-Project/Cortex/milestone/22) (2019-07-11) -**Closed issues:** - -- dockerhub sample uses the wrong port [\#203](https://github.com/TheHive-Project/Cortex/issues/203) -- docker version of cortex prints a lot of errors for auth failures [\#205](https://github.com/TheHive-Project/Cortex/issues/205) - **Fixed bugs:** - Login error after Cortex upgrade to 3 [\#199](https://github.com/TheHive-Project/Cortex/issues/199) - docker version of cortex breaks when you don't create a user immediately [\#204](https://github.com/TheHive-Project/Cortex/issues/204) - Responder run displayed as Analyzer run [\#207](https://github.com/TheHive-Project/Cortex/issues/207) +**Closed issues:** + +- dockerhub sample uses the wrong port [\#203](https://github.com/TheHive-Project/Cortex/issues/203) +- docker version of cortex prints a lot of errors for auth failures [\#205](https://github.com/TheHive-Project/Cortex/issues/205) + ## [3.0.0-RC3](https://github.com/TheHive-Project/Cortex/milestone/20) (2019-06-28) **Implemented enhancements:** @@ -108,11 +118,6 @@ ## [2.1.3](https://github.com/TheHive-Project/Cortex/milestone/18) (2019-02-05) -**Implemented enhancements:** - -- Add PAP property to jobs list [\#146](https://github.com/TheHive-Project/Cortex/issues/146) -- Add configuration for drone continuous integration [\#156](https://github.com/TheHive-Project/Cortex/issues/156) - **Closed issues:** - conf/logback.xml: Rotate logs [\#62](https://github.com/TheHive-Project/Cortex/issues/62) @@ -126,6 +131,11 @@ - Unable to disable invalid responders [\#157](https://github.com/TheHive-Project/Cortex/issues/157) - Wrong checks of role when an user is created [\#158](https://github.com/TheHive-Project/Cortex/issues/158) +**Implemented enhancements:** + +- Add PAP property to jobs list [\#146](https://github.com/TheHive-Project/Cortex/issues/146) +- Add configuration for drone continuous integration [\#156](https://github.com/TheHive-Project/Cortex/issues/156) + ## [2.1.2](https://github.com/TheHive-Project/Cortex/milestone/17) (2018-10-12) **Fixed bugs:** @@ -134,18 +144,18 @@ ## [2.1.1](https://github.com/TheHive-Project/Cortex/milestone/16) (2018-10-12) -**Implemented enhancements:** - -- Publish stable versions in beta package channels [\#138](https://github.com/TheHive-Project/Cortex/issues/138) -- Allow Cortex to use a custom root context [\#140](https://github.com/TheHive-Project/Cortex/issues/140) -- Change Debian dependencies [\#141](https://github.com/TheHive-Project/Cortex/issues/141) - **Fixed bugs:** - Console output should not be logged in syslog [\#136](https://github.com/TheHive-Project/Cortex/issues/136) - RPM update replace configuration file [\#137](https://github.com/TheHive-Project/Cortex/issues/137) - Fix Cache column in analyzers admin page [\#139](https://github.com/TheHive-Project/Cortex/issues/139) +**Implemented enhancements:** + +- Publish stable versions in beta package channels [\#138](https://github.com/TheHive-Project/Cortex/issues/138) +- Allow Cortex to use a custom root context [\#140](https://github.com/TheHive-Project/Cortex/issues/140) +- Change Debian dependencies [\#141](https://github.com/TheHive-Project/Cortex/issues/141) + ## [2.1.0](https://github.com/TheHive-Project/Cortex/milestone/15) (2018-09-25) **Implemented enhancements:** @@ -180,10 +190,6 @@ ## [2.0.4](https://github.com/TheHive-Project/Cortex/milestone/13) (2018-04-13) -**Implemented enhancements:** - -- Let a Read/Analyze User Display/Change their API Key [\#89](https://github.com/TheHive-Project/Cortex/issues/89) - **Fixed bugs:** - Install python3 requirements for analyzers in public docker image [\#58](https://github.com/TheHive-Project/Cortex/issues/58) @@ -194,8 +200,17 @@ - Updating users by orgAdmin users fails silently [\#94](https://github.com/TheHive-Project/Cortex/issues/94) - Strictly filter the list of analyzers in the run dialog [\#95](https://github.com/TheHive-Project/Cortex/issues/95) +**Implemented enhancements:** + +- Let a Read/Analyze User Display/Change their API Key [\#89](https://github.com/TheHive-Project/Cortex/issues/89) + ## [2.0.3](https://github.com/TheHive-Project/Cortex/milestone/12) (2018-04-12) +**Fixed bugs:** + +- Version Upgrade of Analyzer makes all Analyzers invisible for TheHive (Cortex2) [\#75](https://github.com/TheHive-Project/Cortex/issues/75) +- Refresh Analyzers button not working [\#83](https://github.com/TheHive-Project/Cortex/issues/83) + **Implemented enhancements:** - Allow configuring auto artifacts extraction per analyzer [\#80](https://github.com/TheHive-Project/Cortex/issues/80) @@ -204,11 +219,6 @@ - Allow specifying a cache period per analyzer [\#85](https://github.com/TheHive-Project/Cortex/issues/85) - Allow arbitrary parameters for a job [\#86](https://github.com/TheHive-Project/Cortex/issues/86) -**Fixed bugs:** - -- Version Upgrade of Analyzer makes all Analyzers invisible for TheHive (Cortex2) [\#75](https://github.com/TheHive-Project/Cortex/issues/75) -- Refresh Analyzers button not working [\#83](https://github.com/TheHive-Project/Cortex/issues/83) - ## [2.0.2](https://github.com/TheHive-Project/Cortex/milestone/11) (2018-04-04) **Fixed bugs:** @@ -263,17 +273,17 @@ ## [1.1.2](https://github.com/TheHive-Project/Cortex/milestone/6) (2017-06-12) -**Implemented enhancements:** - -- Initialize MISP modules at startup [\#28](https://github.com/TheHive-Project/Cortex/issues/28) -- Add page loader [\#30](https://github.com/TheHive-Project/Cortex/issues/30) - **Fixed bugs:** - Error 500 in TheHive when a job is submited to Cortex [\#27](https://github.com/TheHive-Project/Cortex/issues/27) - Cortex and MISP unclear and error-loop [\#29](https://github.com/TheHive-Project/Cortex/issues/29) - jobstatus from jobs within cortex are not updated when status changes [\#31](https://github.com/TheHive-Project/Cortex/issues/31) +**Implemented enhancements:** + +- Initialize MISP modules at startup [\#28](https://github.com/TheHive-Project/Cortex/issues/28) +- Add page loader [\#30](https://github.com/TheHive-Project/Cortex/issues/30) + ## [1.1.1](https://github.com/TheHive-Project/Cortex/milestone/5) (2017-05-17) **Implemented enhancements:** diff --git a/project/Common.scala b/project/Common.scala index 4a61bdbde..fe7ffdd6d 100644 --- a/project/Common.scala +++ b/project/Common.scala @@ -24,11 +24,11 @@ object Common { "-Ywarn-nullary-override", // Warn when non-nullary overrides nullary, e.g. def foo() over def foo. "-Ywarn-numeric-widen" // Warn when numerics are widened. ), - scalacOptions in Test ~= { options => + Test / scalacOptions ~= { options => options filterNot (_ == "-Ywarn-dead-code") // Allow dead code in tests (to support using mockito). }, - parallelExecution in Test := false, - fork in Test := true, + Test / parallelExecution := false, + Test / fork := true, javaOptions += "-Xmx1G", // Redirect logs from ElasticSearch (which uses log4j2) to slf4j libraryDependencies += "org.apache.logging.log4j" % "log4j-to-slf4j" % "2.9.1", diff --git a/project/Dependencies.scala b/project/Dependencies.scala index c56ee6473..3ee6e24ef 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -18,7 +18,7 @@ object Dependencies { val reflections = "org.reflections" % "reflections" % "0.9.11" val zip4j = "net.lingala.zip4j" % "zip4j" % "1.3.2" - val elastic4play = "org.thehive-project" %% "elastic4play" % "1.13.2" + val elastic4play = "org.thehive-project" %% "elastic4play" % "1.13.3" val dockerClient = "com.spotify" % "docker-client" % "8.14.4" val akkaCluster = "com.typesafe.akka" %% "akka-cluster" % play.core.PlayVersion.akkaVersion val akkaClusterTyped = "com.typesafe.akka" %% "akka-cluster-typed" % play.core.PlayVersion.akkaVersion diff --git a/version.sbt b/version.sbt index 7b92e2c5a..646259b53 100644 --- a/version.sbt +++ b/version.sbt @@ -1 +1 @@ -ThisBuild / version := "3.1.1-1" +ThisBuild / version := "3.1.2-1"