add sudo to cmd and sh
This commit is contained in:
parent
b3afde6c93
commit
5eaf320d58
5 changed files with 67 additions and 19 deletions
|
@ -118,12 +118,12 @@ open class Prov protected constructor(private val processor: Processor, val name
|
|||
|
||||
|
||||
/**
|
||||
* Execute commands using the shell
|
||||
* Executes a command by using the shell.
|
||||
* Be aware: Executing shell commands that incorporate unsanitized input from an untrusted source
|
||||
* makes a program vulnerable to shell injection, a serious security flaw which can result in arbitrary command execution.
|
||||
* Thus, the use of this method is strongly discouraged in cases where the command string is constructed from external input.
|
||||
*/
|
||||
open fun cmd(cmd: String, dir: String? = null): ProvResult {
|
||||
open fun cmd(cmd: String, dir: String? = null, sudo: Boolean = false): ProvResult {
|
||||
throw Exception("Not implemented")
|
||||
}
|
||||
|
||||
|
@ -132,7 +132,7 @@ open class Prov protected constructor(private val processor: Processor, val name
|
|||
* Same as method cmd but without logging of the result/output, should be used e.g. if secrets are involved.
|
||||
* Attention: only result is NOT logged the executed command still is.
|
||||
*/
|
||||
open fun cmdNoLog(cmd: String, dir: String? = null): ProvResult {
|
||||
open fun cmdNoLog(cmd: String, dir: String? = null, sudo: Boolean = false): ProvResult {
|
||||
throw Exception("Not implemented")
|
||||
}
|
||||
|
||||
|
@ -141,7 +141,7 @@ open class Prov protected constructor(private val processor: Processor, val name
|
|||
* Same as method cmd but without evaluating the result for the overall success.
|
||||
* Can be used e.g. for checks which might succeed or fail but where failure should not influence overall success
|
||||
*/
|
||||
open fun cmdNoEval(cmd: String, dir: String? = null): ProvResult {
|
||||
open fun cmdNoEval(cmd: String, dir: String? = null, sudo: Boolean = false): ProvResult {
|
||||
throw Exception("Not implemented")
|
||||
}
|
||||
|
||||
|
@ -184,7 +184,7 @@ open class Prov protected constructor(private val processor: Processor, val name
|
|||
* Multi-line commands within the script are not supported.
|
||||
* Empty lines and comments (all text behind # in a line) are supported, i.e. they are ignored.
|
||||
*/
|
||||
fun sh(script: String) = def {
|
||||
fun sh(script: String, dir: String? = null, sudo: Boolean = false) = def {
|
||||
val lines = script.trimIndent().replace("\r\n", "\n").split("\n")
|
||||
val linesWithoutComments = lines.stream().map { it.split("#")[0] }
|
||||
val linesNonEmpty = linesWithoutComments.filter { it.trim().isNotEmpty() }
|
||||
|
@ -193,7 +193,7 @@ open class Prov protected constructor(private val processor: Processor, val name
|
|||
|
||||
for (cmd in linesNonEmpty) {
|
||||
if (success) {
|
||||
success = success && cmd(cmd).success
|
||||
success = success && cmd(cmd, dir, sudo).success
|
||||
}
|
||||
}
|
||||
ProvResult(success)
|
||||
|
|
|
@ -2,6 +2,7 @@ package io.provs.platforms
|
|||
|
||||
import io.provs.Prov
|
||||
import io.provs.ProvResult
|
||||
import io.provs.escapeAndEncloseByDoubleQuoteForShell
|
||||
import io.provs.processors.LocalProcessor
|
||||
import io.provs.processors.Processor
|
||||
|
||||
|
@ -10,15 +11,24 @@ const val SHELL = "/bin/bash" // could be changed to another shell like "sh", "
|
|||
|
||||
class UbuntuProv internal constructor(processor : Processor = LocalProcessor(), name: String? = null) : Prov (processor, name) {
|
||||
|
||||
override fun cmd(cmd: String, dir: String?) : ProvResult = def {
|
||||
xec(SHELL, "-c", if (dir == null) cmd else "cd $dir && $cmd")
|
||||
override fun cmd(cmd: String, dir: String?, sudo: Boolean) : ProvResult = def {
|
||||
xec(SHELL, "-c", commandWithDirAndSudo(cmd, dir, sudo))
|
||||
}
|
||||
|
||||
override fun cmdNoLog(cmd: String, dir: String?) : ProvResult {
|
||||
return xecNoLog(SHELL, "-c", if (dir == null) cmd else "cd $dir && $cmd")
|
||||
override fun cmdNoLog(cmd: String, dir: String?, sudo: Boolean) : ProvResult {
|
||||
return xecNoLog(SHELL, "-c", commandWithDirAndSudo(cmd, dir, sudo))
|
||||
}
|
||||
|
||||
override fun cmdNoEval(cmd: String, dir: String?) : ProvResult {
|
||||
return xec(SHELL, "-c", if (dir == null) cmd else "cd $dir && $cmd")
|
||||
override fun cmdNoEval(cmd: String, dir: String?, sudo: Boolean) : ProvResult {
|
||||
return xec(SHELL, "-c", commandWithDirAndSudo(cmd, dir, sudo))
|
||||
}
|
||||
}
|
||||
|
||||
private fun commandWithDirAndSudo(cmd: String, dir: String?, sudo: Boolean): String {
|
||||
val cmdWithDir= if (dir == null) cmd else "cd $dir && $cmd"
|
||||
return if (sudo) cmdWithDir.sudoize() else cmdWithDir
|
||||
}
|
||||
|
||||
private fun String.sudoize(): String {
|
||||
return "sudo " + SHELL + " -c " + this.escapeAndEncloseByDoubleQuoteForShell()
|
||||
}
|
|
@ -8,18 +8,21 @@ import io.provs.processors.Processor
|
|||
|
||||
class WinProv internal constructor(processor : Processor = LocalProcessor(), name: String? = null) : Prov (processor, name) {
|
||||
|
||||
// todo put cmd.exe in variable SHELL
|
||||
private val SHELL = "cmd.exe"
|
||||
|
||||
override fun cmd(cmd: String, dir: String?) : ProvResult = def {
|
||||
xec("cmd.exe", "/c", if (dir == null) cmd else "cd $dir && $cmd")
|
||||
override fun cmd(cmd: String, dir: String?, sudo: Boolean) : ProvResult = def {
|
||||
require(!sudo, {"sudo not supported"})
|
||||
xec(SHELL, "/c", if (dir == null) cmd else "cd $dir && $cmd")
|
||||
}
|
||||
|
||||
override fun cmdNoLog(cmd: String, dir: String?) : ProvResult = def {
|
||||
xecNoLog("cmd.exe", "/c", if (dir == null) cmd else "cd $dir && $cmd")
|
||||
override fun cmdNoLog(cmd: String, dir: String?, sudo: Boolean) : ProvResult = def {
|
||||
require(!sudo, {"sudo not supported"})
|
||||
xecNoLog(SHELL, "/c", if (dir == null) cmd else "cd $dir && $cmd")
|
||||
}
|
||||
|
||||
|
||||
override fun cmdNoEval(cmd: String, dir: String?) : ProvResult {
|
||||
return xec("cmd.exe", "/c", if (dir == null) cmd else "cd $dir && $cmd")
|
||||
override fun cmdNoEval(cmd: String, dir: String?, sudo: Boolean) : ProvResult {
|
||||
require(!sudo, {"sudo not supported"})
|
||||
return xec(SHELL, "/c", if (dir == null) cmd else "cd $dir && $cmd")
|
||||
}
|
||||
}
|
|
@ -53,6 +53,27 @@ internal class ProvTest {
|
|||
assert(res)
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledOnOs(OS.LINUX)
|
||||
@ContainerTest
|
||||
fun sh_onLinux_with_dir_and_sudo() {
|
||||
// given
|
||||
val script = """
|
||||
# test some script commands
|
||||
|
||||
ping -c1 google.com
|
||||
echo something
|
||||
ping -c1 github.com
|
||||
echo 1 # comment behind command
|
||||
"""
|
||||
|
||||
// when
|
||||
val res = Prov.newInstance(name = "provs_test").sh(script, "/root", true).success
|
||||
|
||||
// then
|
||||
assert(res)
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@EnabledOnOs(OS.WINDOWS)
|
||||
|
|
|
@ -44,6 +44,20 @@ internal class UbuntuProvTests {
|
|||
assert(res2.out?.trim() == "abc")
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledOnOs(OS.LINUX)
|
||||
fun that_cmd_works_with_sudo() {
|
||||
// given
|
||||
val a = Prov.defaultInstance()
|
||||
|
||||
// when
|
||||
val res1 = a.cmd("echo abc", "/root", sudo = true)
|
||||
|
||||
// then
|
||||
assert(res1.success)
|
||||
assert(res1.out?.trim() == "abc")
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledOnOs(OS.LINUX)
|
||||
fun that_nested_shells_work() {
|
||||
|
|
Loading…
Reference in a new issue