From 0aa133d2762aad2ea3a52d77dbbbac8bdc3dc0f6 Mon Sep 17 00:00:00 2001 From: Steve Waldman Date: Mon, 5 Feb 2018 23:11:42 -0800 Subject: [PATCH 1/3] Implement 'suppressServer' setting, for builds and plugins that prefer to be conservative about exposure to other processes. --- main-command/src/main/scala/sbt/BasicKeys.scala | 6 ++++++ main/src/main/scala/sbt/Defaults.scala | 1 + main/src/main/scala/sbt/Keys.scala | 1 + main/src/main/scala/sbt/Project.scala | 3 +++ main/src/main/scala/sbt/internal/CommandExchange.scala | 7 ++++++- 5 files changed, 17 insertions(+), 1 deletion(-) diff --git a/main-command/src/main/scala/sbt/BasicKeys.scala b/main-command/src/main/scala/sbt/BasicKeys.scala index 86dd9343f..a820515db 100644 --- a/main-command/src/main/scala/sbt/BasicKeys.scala +++ b/main-command/src/main/scala/sbt/BasicKeys.scala @@ -39,6 +39,12 @@ object BasicKeys { "The wire protocol for the server command.", 10000) + val suppressServer = + AttributeKey[Boolean]( + "suppressServer", + "Running the server will be suppressed if 'suppressServer is explicitly set to true.", + 10000) + // Unlike other BasicKeys, this is not used directly as a setting key, // and severLog / logLevel is used instead. private[sbt] val serverLogLevel = diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 721e08914..35c9db19d 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -268,6 +268,7 @@ object Defaults extends BuildCommon { .getOrElse(GCUtil.defaultForceGarbageCollection), minForcegcInterval :== GCUtil.defaultMinForcegcInterval, interactionService :== CommandLineUIService, + suppressServer := false, serverHost := "127.0.0.1", serverPort := 5000 + (Hash .toHex(Hash(appConfiguration.value.baseDirectory.toString)) diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index bfcb3139e..1d32e2bb5 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -131,6 +131,7 @@ object Keys { // Command keys val historyPath = SettingKey(BasicKeys.historyPath) val shellPrompt = SettingKey(BasicKeys.shellPrompt) + val suppressServer = SettingKey(BasicKeys.suppressServer) val serverPort = SettingKey(BasicKeys.serverPort) val serverHost = SettingKey(BasicKeys.serverHost) val serverAuthentication = SettingKey(BasicKeys.serverAuthentication) diff --git a/main/src/main/scala/sbt/Project.scala b/main/src/main/scala/sbt/Project.scala index fd175f6c6..bd9fe8b0b 100755 --- a/main/src/main/scala/sbt/Project.scala +++ b/main/src/main/scala/sbt/Project.scala @@ -21,6 +21,7 @@ import Keys.{ sessionSettings, shellPrompt, templateResolverInfos, + suppressServer, serverHost, serverLog, serverPort, @@ -462,6 +463,7 @@ object Project extends ProjectExtra { val prompt = get(shellPrompt) val trs = (templateResolverInfos in Global get structure.data).toList.flatten val watched = get(watch) + val suppressSvr: Option[Boolean] = get(suppressServer) val host: Option[String] = get(serverHost) val port: Option[Int] = get(serverPort) val authentication: Option[Set[ServerAuthentication]] = get(serverAuthentication) @@ -474,6 +476,7 @@ object Project extends ProjectExtra { s.attributes .setCond(Watched.Configuration, watched) .put(historyPath.key, history) + .setCond(suppressServer.key, suppressSvr) .setCond(serverPort.key, port) .setCond(serverHost.key, host) .setCond(serverAuthentication.key, authentication) diff --git a/main/src/main/scala/sbt/internal/CommandExchange.scala b/main/src/main/scala/sbt/internal/CommandExchange.scala index d7b52280d..eeadfad33 100644 --- a/main/src/main/scala/sbt/internal/CommandExchange.scala +++ b/main/src/main/scala/sbt/internal/CommandExchange.scala @@ -14,6 +14,7 @@ import java.util.concurrent.atomic._ import scala.collection.mutable.ListBuffer import scala.annotation.tailrec import BasicKeys.{ + suppressServer, serverHost, serverPort, serverAuthentication, @@ -87,7 +88,11 @@ private[sbt] final class CommandExchange { consoleChannel = Some(x) subscribe(x) } - if (autoStartServer) runServer(s) + val suppress = (s get suppressServer) match { + case Some(bool) => bool + case None => false + } + if (autoStartServer && !suppress) runServer(s) else s } From 9601668199cd52d6fa37aecae4cbda10920f89bf Mon Sep 17 00:00:00 2001 From: Steve Waldman Date: Mon, 5 Feb 2018 23:35:31 -0800 Subject: [PATCH 2/3] Add a note describing the suppressServer feature. --- notes/1.1.1/suppressServer.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 notes/1.1.1/suppressServer.md diff --git a/notes/1.1.1/suppressServer.md b/notes/1.1.1/suppressServer.md new file mode 100644 index 000000000..0e9fdce79 --- /dev/null +++ b/notes/1.1.1/suppressServer.md @@ -0,0 +1,23 @@ +### Improvements + +This pull request implements a Boolean setting called `suppressServer`, whose default value is `false'. + +If a build or plugin explicitly sets it to `true`, the sbt-1.x server will not start up +(exactly as if `sbt.server.autostart` were set to start). + +Users may manually override this setting by running the `startServer` command at the interactive prompt. + +### Motivation + +Projects often encounter private information, such as deployment credentials, private keys, etc. +For such projects, it may be preferable to reduce the potential attack surface than to enjoy the +interoperability offered by sbt's server. Projects that wish to make this tradeoff can set `suppressServer` +to `true` in their build. Security-sensitive plugins can define this setting as well, modifying the +default behavior in favor of security. + +(My own motivation is that I am working on a [plugin for developing Ethereum applications](https://github.com/swaldman/sbt-ethereum) +with scala and sbt. It must work with extremely sensitive private keys.) + +--- + +See also a [recent conversation on Stack Exchange](https://stackoverflow.com/questions/48591179/can-one-disable-the-sbt-1-x-server/48593906#48593906). From 96b94296693a31fd4db61444b264f53bf718ee38 Mon Sep 17 00:00:00 2001 From: Steve Waldman Date: Tue, 6 Feb 2018 11:49:46 -0800 Subject: [PATCH 3/3] Rework false-defaulting 'suppressServer' to true-defaulting 'autoStartServer'. --- .../src/main/scala/sbt/BasicKeys.scala | 6 ++-- main/src/main/scala/sbt/Defaults.scala | 2 +- main/src/main/scala/sbt/Keys.scala | 2 +- main/src/main/scala/sbt/Project.scala | 6 ++-- .../scala/sbt/internal/CommandExchange.scala | 10 +++--- notes/1.1.1/autoStartServer.md | 31 +++++++++++++++++++ notes/1.1.1/suppressServer.md | 23 -------------- 7 files changed, 44 insertions(+), 36 deletions(-) create mode 100644 notes/1.1.1/autoStartServer.md delete mode 100644 notes/1.1.1/suppressServer.md diff --git a/main-command/src/main/scala/sbt/BasicKeys.scala b/main-command/src/main/scala/sbt/BasicKeys.scala index a820515db..1570d392b 100644 --- a/main-command/src/main/scala/sbt/BasicKeys.scala +++ b/main-command/src/main/scala/sbt/BasicKeys.scala @@ -39,10 +39,10 @@ object BasicKeys { "The wire protocol for the server command.", 10000) - val suppressServer = + val autoStartServer = AttributeKey[Boolean]( - "suppressServer", - "Running the server will be suppressed if 'suppressServer is explicitly set to true.", + "autoStartServer", + "If true, the sbt server will startup automatically during interactive sessions.", 10000) // Unlike other BasicKeys, this is not used directly as a setting key, diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 35c9db19d..b9ab939ef 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -268,7 +268,7 @@ object Defaults extends BuildCommon { .getOrElse(GCUtil.defaultForceGarbageCollection), minForcegcInterval :== GCUtil.defaultMinForcegcInterval, interactionService :== CommandLineUIService, - suppressServer := false, + autoStartServer := true, serverHost := "127.0.0.1", serverPort := 5000 + (Hash .toHex(Hash(appConfiguration.value.baseDirectory.toString)) diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index 1d32e2bb5..8e26b54fb 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -131,7 +131,7 @@ object Keys { // Command keys val historyPath = SettingKey(BasicKeys.historyPath) val shellPrompt = SettingKey(BasicKeys.shellPrompt) - val suppressServer = SettingKey(BasicKeys.suppressServer) + val autoStartServer = SettingKey(BasicKeys.autoStartServer) val serverPort = SettingKey(BasicKeys.serverPort) val serverHost = SettingKey(BasicKeys.serverHost) val serverAuthentication = SettingKey(BasicKeys.serverAuthentication) diff --git a/main/src/main/scala/sbt/Project.scala b/main/src/main/scala/sbt/Project.scala index bd9fe8b0b..f292ca0e1 100755 --- a/main/src/main/scala/sbt/Project.scala +++ b/main/src/main/scala/sbt/Project.scala @@ -21,7 +21,7 @@ import Keys.{ sessionSettings, shellPrompt, templateResolverInfos, - suppressServer, + autoStartServer, serverHost, serverLog, serverPort, @@ -463,7 +463,7 @@ object Project extends ProjectExtra { val prompt = get(shellPrompt) val trs = (templateResolverInfos in Global get structure.data).toList.flatten val watched = get(watch) - val suppressSvr: Option[Boolean] = get(suppressServer) + val startSvr: Option[Boolean] = get(autoStartServer) val host: Option[String] = get(serverHost) val port: Option[Int] = get(serverPort) val authentication: Option[Set[ServerAuthentication]] = get(serverAuthentication) @@ -476,7 +476,7 @@ object Project extends ProjectExtra { s.attributes .setCond(Watched.Configuration, watched) .put(historyPath.key, history) - .setCond(suppressServer.key, suppressSvr) + .setCond(autoStartServer.key, startSvr) .setCond(serverPort.key, port) .setCond(serverHost.key, host) .setCond(serverAuthentication.key, authentication) diff --git a/main/src/main/scala/sbt/internal/CommandExchange.scala b/main/src/main/scala/sbt/internal/CommandExchange.scala index eeadfad33..0b68cae24 100644 --- a/main/src/main/scala/sbt/internal/CommandExchange.scala +++ b/main/src/main/scala/sbt/internal/CommandExchange.scala @@ -14,7 +14,7 @@ import java.util.concurrent.atomic._ import scala.collection.mutable.ListBuffer import scala.annotation.tailrec import BasicKeys.{ - suppressServer, + autoStartServer, serverHost, serverPort, serverAuthentication, @@ -44,7 +44,7 @@ import sbt.util.{ Level, Logger, LogExchange } * this exchange, which could serve command request from either of the channel. */ private[sbt] final class CommandExchange { - private val autoStartServer = sys.props.get("sbt.server.autostart") map { + private val autoStartServerSysProp = sys.props.get("sbt.server.autostart") map { _.toLowerCase == "true" } getOrElse true private val lock = new AnyRef {} @@ -88,11 +88,11 @@ private[sbt] final class CommandExchange { consoleChannel = Some(x) subscribe(x) } - val suppress = (s get suppressServer) match { + val autoStartServerAttr = (s get autoStartServer) match { case Some(bool) => bool - case None => false + case None => true } - if (autoStartServer && !suppress) runServer(s) + if (autoStartServerSysProp && autoStartServerAttr) runServer(s) else s } diff --git a/notes/1.1.1/autoStartServer.md b/notes/1.1.1/autoStartServer.md new file mode 100644 index 000000000..cc00c3fbc --- /dev/null +++ b/notes/1.1.1/autoStartServer.md @@ -0,0 +1,31 @@ +### Improvements + +This pull request implements a Boolean setting called `autoStartServer`, whose default value is `true'. + +If a build or plugin explicitly sets it to `false`, the sbt-1.x server will not start up +(exactly as if the system property `sbt.server.autostart` were set to `false`). + +Users who set `autoStartServer` to `false` may manually execute `startServer` at the interactive prompt, +if they wish to use the server during a shell session. + +### Motivation + +Projects often encounter private information, such as deployment credentials, private keys, etc. +For such projects, it may be preferable to reduce the potential attack surface than to enjoy the +interoperability offered by sbt's server. Projects that wish to make this tradeoff can set `autoStartServer` +to `false` in their build. Security-sensitive plugins can disable `autoStartServer` as well, modifying the +default behavior in favor of security. + +(My own motivation is that I am working on a [plugin for developing Ethereum applications](https://github.com/swaldman/sbt-ethereum) +with scala and sbt. It must work with extremely sensitive private keys.) + +--- + +See also a [recent conversation on Stack Exchange](https://stackoverflow.com/questions/48591179/can-one-disable-the-sbt-1-x-server/48593906#48593906). + +--- + +##### History + +2018-02-06 Modified from negative `suppressServer` to positive `autoStartServer` at the (sensible) request of @eed3si9n + diff --git a/notes/1.1.1/suppressServer.md b/notes/1.1.1/suppressServer.md deleted file mode 100644 index 0e9fdce79..000000000 --- a/notes/1.1.1/suppressServer.md +++ /dev/null @@ -1,23 +0,0 @@ -### Improvements - -This pull request implements a Boolean setting called `suppressServer`, whose default value is `false'. - -If a build or plugin explicitly sets it to `true`, the sbt-1.x server will not start up -(exactly as if `sbt.server.autostart` were set to start). - -Users may manually override this setting by running the `startServer` command at the interactive prompt. - -### Motivation - -Projects often encounter private information, such as deployment credentials, private keys, etc. -For such projects, it may be preferable to reduce the potential attack surface than to enjoy the -interoperability offered by sbt's server. Projects that wish to make this tradeoff can set `suppressServer` -to `true` in their build. Security-sensitive plugins can define this setting as well, modifying the -default behavior in favor of security. - -(My own motivation is that I am working on a [plugin for developing Ethereum applications](https://github.com/swaldman/sbt-ethereum) -with scala and sbt. It must work with extremely sensitive private keys.) - ---- - -See also a [recent conversation on Stack Exchange](https://stackoverflow.com/questions/48591179/can-one-disable-the-sbt-1-x-server/48593906#48593906).