Merge branch 'local-sudoer-without-pw' into 'master'
Local sudoer without pw See merge request domaindrivenarchitecture/provs!6
This commit is contained in:
commit
c82abbb3db
10 changed files with 122 additions and 71 deletions
55
doc/CreateProvInstanceSequence.md
Normal file
55
doc/CreateProvInstanceSequence.md
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
|
||||||
|
autonumber
|
||||||
|
|
||||||
|
skinparam sequenceBox {
|
||||||
|
borderColor White
|
||||||
|
}
|
||||||
|
|
||||||
|
participant Cli
|
||||||
|
participant Application
|
||||||
|
participant CliArgumentsParser
|
||||||
|
participant CliTargetCommand
|
||||||
|
participant CliUtils
|
||||||
|
participant "CliUtils\ncreateLocalProv" as CliUtilsL
|
||||||
|
participant "CliUtils\ncreateRemoteProv" as CliUtilsR
|
||||||
|
participant Prov
|
||||||
|
participant PromptSecretSource
|
||||||
|
participant User
|
||||||
|
|
||||||
|
Cli -> Application ++ : main(args...)
|
||||||
|
Application -> CliArgumentsParser : parseCommand
|
||||||
|
|
||||||
|
CliArgumentsParser -> CliTargetCommand : create()
|
||||||
|
Application -> CliUtils : createProvInstance( targetCliCommand )
|
||||||
|
alt target.isValidLocal
|
||||||
|
CliUtils -> CliUtilsL : createLocalProv
|
||||||
|
CliUtilsL -> Prov : createLocalInstance
|
||||||
|
alt userCannotSudoWithoutPw
|
||||||
|
CliUtilsL -> PromptSecretSource : getPassword
|
||||||
|
CliUtilsL -> User : makeUserSudoWithoutPw
|
||||||
|
CliUtilsL --> CliUtils : provInstance
|
||||||
|
CliUtils --> Application : provInstance
|
||||||
|
end
|
||||||
|
else target.isValidRemote
|
||||||
|
CliUtils -> CliUtilsR : createRemoteProv
|
||||||
|
CliUtilsR -> Prov : createRemoteInstance
|
||||||
|
alt userCannotSudoWithoutPw
|
||||||
|
CliUtilsR -> PromptSecretSource : getPassword
|
||||||
|
CliUtilsR -> User : makeUserSudoWithoutPw
|
||||||
|
CliUtilsR -> Prov : createRemoteInstance\n[new ssh-client is required]
|
||||||
|
CliUtilsR --> CliUtils : provInstance
|
||||||
|
CliUtils --> Application : provInstance
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Application -> DesktopService1 : provisionDesktopCommand ( provInstance, desktopCliCommand )
|
||||||
|
|
||||||
|
|
||||||
|
'DesktopService1 -> DesktopService2 : provisionDesktop( config )
|
||||||
|
'DesktopService1 -> ConfigRepository : getConfig
|
||||||
|
|
||||||
|
@enduml
|
||||||
|
|
||||||
|
```
|
|
@ -24,7 +24,6 @@ CliArgumentsParser -> DesktopCliCommand : create(desktopType, cliTargetCmd, ...)
|
||||||
CliArgumentsParser --> Application: desktopCliCommand
|
CliArgumentsParser --> Application: desktopCliCommand
|
||||||
Application -> DesktopCliCommand : isValid ?
|
Application -> DesktopCliCommand : isValid ?
|
||||||
Application -> CliUtils : createProvInstance
|
Application -> CliUtils : createProvInstance
|
||||||
ProvInstance <- CliUtils : create
|
|
||||||
alt target.isValidLocal
|
alt target.isValidLocal
|
||||||
CliUtils -> CliUtils : createLocalProv
|
CliUtils -> CliUtils : createLocalProv
|
||||||
else target.isValidRemote
|
else target.isValidRemote
|
||||||
|
|
|
@ -17,7 +17,7 @@ fun main(args: Array<String>) {
|
||||||
exitProcess(1)
|
exitProcess(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
val prov = createProvInstance(cmd.target, remoteHostSetSudoWithoutPasswordRequired = true)
|
val prov = createProvInstance(cmd.target)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
provisionDesktopCommand(prov, cmd)
|
provisionDesktopCommand(prov, cmd)
|
||||||
|
|
|
@ -7,42 +7,39 @@ import org.domaindrivenarchitecture.provs.framework.core.local
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.remote
|
import org.domaindrivenarchitecture.provs.framework.core.remote
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.secret.secretSources.PromptSecretSource
|
import org.domaindrivenarchitecture.provs.framework.ubuntu.secret.secretSources.PromptSecretSource
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.user.base.currentUserCanSudoWithoutPassword
|
import org.domaindrivenarchitecture.provs.framework.ubuntu.user.base.currentUserCanSudoWithoutPassword
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.user.base.makeUserSudoerWithNoSudoPasswordRequired
|
import org.domaindrivenarchitecture.provs.framework.ubuntu.user.base.makeCurrentUserSudoerWithoutPasswordRequired
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.user.base.whoami
|
import org.domaindrivenarchitecture.provs.framework.ubuntu.user.base.whoami
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a Prov instance according to the targetCommand.
|
* Returns a Prov instance according to the targetCommand.
|
||||||
* E.g. it returns a local Prov instance if targetCommand.isValidLocalhost() is true or
|
* Returns a local Prov instance if targetCommand.isValidLocalhost() is true resp.
|
||||||
* returns a remote Prov instance if targetCommand.isValidRemote() is true.
|
* returns a remote Prov instance if targetCommand.isValidRemote() is true.
|
||||||
*
|
|
||||||
* If the target is remote and if parameter remoteHostSetSudoWithoutPasswordRequired is set to true,
|
|
||||||
* it will enable sudo without password on the remote machine (in case this was not yet enabled).
|
|
||||||
*/
|
*/
|
||||||
fun createProvInstance(
|
fun createProvInstance(targetCommand: TargetCliCommand): Prov {
|
||||||
targetCommand: TargetCliCommand,
|
|
||||||
remoteHostSetSudoWithoutPasswordRequired: Boolean = false
|
|
||||||
): Prov {
|
|
||||||
if (targetCommand.isValid()) {
|
if (targetCommand.isValid()) {
|
||||||
val password: Secret? = targetCommand.remoteTarget()?.password
|
val password: Secret? = targetCommand.remoteTarget()?.password
|
||||||
|
|
||||||
val remoteTarget = targetCommand.remoteTarget()
|
val remoteTarget = targetCommand.remoteTarget()
|
||||||
if (targetCommand.isValidLocalhost()) {
|
|
||||||
return createLocalProvInstance()
|
return if (targetCommand.isValidLocalhost()) {
|
||||||
|
createLocalProvInstance()
|
||||||
} else if (targetCommand.isValidRemote() && remoteTarget != null) {
|
} else if (targetCommand.isValidRemote() && remoteTarget != null) {
|
||||||
return createRemoteProvInstance(
|
createRemoteProvInstance(
|
||||||
remoteTarget.host,
|
remoteTarget.host,
|
||||||
remoteTarget.user,
|
remoteTarget.user,
|
||||||
remoteTarget.password == null,
|
remoteTarget.password == null,
|
||||||
password,
|
password
|
||||||
remoteHostSetSudoWithoutPasswordRequired
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
throw IllegalArgumentException("Error: neither a valid localHost nor a valid remoteHost was specified! Use option -h for help.")
|
throw IllegalArgumentException(
|
||||||
|
"Error: neither a valid localHost nor a valid remoteHost was specified! Use option -h for help."
|
||||||
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
println("Invalid command line options.\nPlease use option -h for help.")
|
println("ERROR: Invalid target (${targetCommand.target}). Please use option -h for help.")
|
||||||
|
System.out.flush()
|
||||||
exitProcess(1)
|
exitProcess(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,9 +47,13 @@ fun createProvInstance(
|
||||||
private fun createLocalProvInstance(): Prov {
|
private fun createLocalProvInstance(): Prov {
|
||||||
val prov = local()
|
val prov = local()
|
||||||
if (!prov.currentUserCanSudoWithoutPassword()) {
|
if (!prov.currentUserCanSudoWithoutPassword()) {
|
||||||
val password = PromptSecretSource("Please enter password to configure sudo without password in the future." +
|
val passwordNonNull = getPasswordToConfigureSudoWithoutPassword()
|
||||||
"\nWarning: This will permanently allow your user to use sudo privileges without a password.").secret()
|
|
||||||
prov.makeUserSudoerWithNoSudoPasswordRequired(password)
|
prov.makeCurrentUserSudoerWithoutPasswordRequired(passwordNonNull)
|
||||||
|
|
||||||
|
check(prov.currentUserCanSudoWithoutPassword()) {
|
||||||
|
"ERROR: User ${prov.whoami()} cannot sudo without enteringa password."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return prov
|
return prov
|
||||||
}
|
}
|
||||||
|
@ -62,42 +63,43 @@ private fun createRemoteProvInstance(
|
||||||
host: String,
|
host: String,
|
||||||
remoteUser: String,
|
remoteUser: String,
|
||||||
sshWithKey: Boolean,
|
sshWithKey: Boolean,
|
||||||
password: Secret?,
|
password: Secret?
|
||||||
remoteHostSetSudoWithoutPasswordRequired: Boolean
|
|
||||||
): Prov {
|
): Prov {
|
||||||
val prov =
|
val prov =
|
||||||
if (sshWithKey) {
|
if (sshWithKey) {
|
||||||
remote(host, remoteUser)
|
remote(host, remoteUser)
|
||||||
} else {
|
} else {
|
||||||
require(
|
require(password != null) {
|
||||||
password != null,
|
"No password available for provisioning without ssh keys. " +
|
||||||
{ "No password available for provisioning without ssh keys. Either specify provisioning by ssh-keys or provide password." })
|
"Either specify provisioning by ssh-keys or provide password."
|
||||||
|
}
|
||||||
remote(host, remoteUser, password)
|
remote(host, remoteUser, password)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!prov.currentUserCanSudoWithoutPassword()) {
|
return if (prov.currentUserCanSudoWithoutPassword()) {
|
||||||
if (remoteHostSetSudoWithoutPasswordRequired) {
|
prov
|
||||||
require(
|
} else {
|
||||||
password != null,
|
|
||||||
{ "User ${prov.whoami()} not able to sudo on remote machine without password and no password available for the user." })
|
|
||||||
prov.makeUserSudoerWithNoSudoPasswordRequired(password)
|
|
||||||
|
|
||||||
// a new session is required after making the user a sudoer without password
|
val passwordNonNull = password
|
||||||
return remote(host, remoteUser, password)
|
?: getPasswordToConfigureSudoWithoutPassword()
|
||||||
} else {
|
|
||||||
throw IllegalStateException("User ${prov.whoami()} not able to sudo on remote machine without password and option not set to enable user to sudo without password.")
|
val result = prov.makeCurrentUserSudoerWithoutPasswordRequired(passwordNonNull)
|
||||||
|
|
||||||
|
check(result.success) {
|
||||||
|
"Could not make user a sudoer without password required. (Maybe the provided password is incorrect.)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// a new session is required after the user has become a sudoer without password
|
||||||
|
val provWithNewSshClient = remote(host, remoteUser, password)
|
||||||
|
|
||||||
|
check(provWithNewSshClient.currentUserCanSudoWithoutPassword()) {
|
||||||
|
"ERROR: User ${provWithNewSshClient.whoami()} on $host cannot sudo without entering a password."
|
||||||
|
}
|
||||||
|
|
||||||
|
provWithNewSshClient
|
||||||
}
|
}
|
||||||
return prov
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun getPasswordToConfigureSudoWithoutPassword(): Secret {
|
||||||
internal fun retrievePassword(cliCommand: TargetCliCommand): Secret? {
|
return PromptSecretSource("password to configure sudo without password.").secret()
|
||||||
var password: Secret? = null
|
}
|
||||||
if (cliCommand.isValidRemote() && cliCommand.passwordInteractive) {
|
|
||||||
password =
|
|
||||||
PromptSecretSource("Password for user $cliCommand.userName!! on $cliCommand.remoteHost!!").secret()
|
|
||||||
|
|
||||||
}
|
|
||||||
return password
|
|
||||||
}
|
|
|
@ -13,13 +13,6 @@ class UbuntuProv internal constructor(
|
||||||
progressType: ProgressType
|
progressType: ProgressType
|
||||||
) : Prov(processor, name, progressType) {
|
) : Prov(processor, name, progressType) {
|
||||||
|
|
||||||
init {
|
|
||||||
val user = cmdNoLog("whoami").out?.trim()
|
|
||||||
if ("root" != user && !cmdNoLog("timeout 1 sudo id").success) {
|
|
||||||
println("IMPORTANT INFO:\nUser $user cannot sudo without entering a password, i.e. some functions may fail!\nIf you need to run functions with sudo, please ensure $user can sudo without password.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun cmd(cmd: String, dir: String?, sudo: Boolean): ProvResult = taskWithResult {
|
override fun cmd(cmd: String, dir: String?, sudo: Boolean): ProvResult = taskWithResult {
|
||||||
exec(SHELL, "-c", commandWithDirAndSudo(cmd, dir, sudo))
|
exec(SHELL, "-c", commandWithDirAndSudo(cmd, dir, sudo))
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,8 @@ class RemoteProcessor(host: InetAddress, user: String, password: Secret? = null)
|
||||||
|
|
||||||
// Attention: host key is not verified
|
// Attention: host key is not verified
|
||||||
ssh.addHostKeyVerifier(PromiscuousVerifier())
|
ssh.addHostKeyVerifier(PromiscuousVerifier())
|
||||||
|
|
||||||
|
ssh.connectTimeout = 30000 // ms
|
||||||
ssh.connect(host)
|
ssh.connect(host)
|
||||||
|
|
||||||
if (password != null) {
|
if (password != null) {
|
||||||
|
@ -50,8 +52,9 @@ class RemoteProcessor(host: InetAddress, user: String, password: Secret? = null)
|
||||||
try {
|
try {
|
||||||
ssh.disconnect()
|
ssh.disconnect()
|
||||||
} finally {
|
} finally {
|
||||||
log.error("Got exception when initializing ssh (Username, password or ssh-key might be wrong): " + e.message)
|
val errorMag = "Error when initializing ssh (Host, username, password or ssh-key might be wrong) "
|
||||||
throw RuntimeException("Error when initializing ssh (Username, password or ssh-key might be wrong) ", e)
|
log.error(errorMag + e.message)
|
||||||
|
throw RuntimeException(errorMag, e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import javax.swing.*
|
||||||
|
|
||||||
class PasswordPanel : JPanel(FlowLayout()) {
|
class PasswordPanel : JPanel(FlowLayout()) {
|
||||||
|
|
||||||
private val passwordField = JPasswordField(20)
|
private val passwordField = JPasswordField(30)
|
||||||
private var entered = false
|
private var entered = false
|
||||||
|
|
||||||
val enteredPassword
|
val enteredPassword
|
||||||
|
|
|
@ -33,7 +33,7 @@ fun Prov.createUser(
|
||||||
}
|
}
|
||||||
password?.let { cmdNoLog("sudo echo \"$userName:${password.plain()}\" | sudo chpasswd") } ?: ProvResult(true)
|
password?.let { cmdNoLog("sudo echo \"$userName:${password.plain()}\" | sudo chpasswd") } ?: ProvResult(true)
|
||||||
if (userCanSudoWithoutPassword) {
|
if (userCanSudoWithoutPassword) {
|
||||||
makeUserSudoerWithNoSudoPasswordRequired(userName)
|
makeUserSudoerWithoutPasswordRequired(userName)
|
||||||
}
|
}
|
||||||
val authorizedKeysFile = userHome() + ".ssh/authorized_keys"
|
val authorizedKeysFile = userHome() + ".ssh/authorized_keys"
|
||||||
if (copyAuthorizedSshKeysFromCurrentUser && checkFile(authorizedKeysFile)) {
|
if (copyAuthorizedSshKeysFromCurrentUser && checkFile(authorizedKeysFile)) {
|
||||||
|
@ -85,11 +85,11 @@ fun Prov.deleteUser(userName: String, deleteHomeDir: Boolean = false): ProvResul
|
||||||
* The current (executing) user must already be a sudoer. If he is a sudoer with password required then
|
* The current (executing) user must already be a sudoer. If he is a sudoer with password required then
|
||||||
* his password must be provided.
|
* his password must be provided.
|
||||||
*/
|
*/
|
||||||
fun Prov.makeUserSudoerWithNoSudoPasswordRequired(
|
fun Prov.makeUserSudoerWithoutPasswordRequired(
|
||||||
userName: String,
|
userName: String,
|
||||||
password: Secret? = null,
|
password: Secret? = null,
|
||||||
overwriteFile: Boolean = false
|
overwriteFile: Boolean = false
|
||||||
): ProvResult = task {
|
): ProvResult = taskWithResult {
|
||||||
val userSudoFile = "/etc/sudoers.d/$userName"
|
val userSudoFile = "/etc/sudoers.d/$userName"
|
||||||
if (!checkFile(userSudoFile) || overwriteFile) {
|
if (!checkFile(userSudoFile) || overwriteFile) {
|
||||||
val sudoPrefix = if (password == null) "sudo" else "echo ${password.plain()} | sudo -S"
|
val sudoPrefix = if (password == null) "sudo" else "echo ${password.plain()} | sudo -S"
|
||||||
|
@ -107,11 +107,10 @@ fun Prov.makeUserSudoerWithNoSudoPasswordRequired(
|
||||||
* Makes the current (executing) user be able to sudo without password.
|
* Makes the current (executing) user be able to sudo without password.
|
||||||
* IMPORTANT: Current user must already by sudoer when calling this function.
|
* IMPORTANT: Current user must already by sudoer when calling this function.
|
||||||
*/
|
*/
|
||||||
@Suppress("unused") // used externally
|
fun Prov.makeCurrentUserSudoerWithoutPasswordRequired(password: Secret) = taskWithResult {
|
||||||
fun Prov.makeUserSudoerWithNoSudoPasswordRequired(password: Secret) = task {
|
|
||||||
val currentUser = whoami()
|
val currentUser = whoami()
|
||||||
if (currentUser != null) {
|
if (currentUser != null) {
|
||||||
makeUserSudoerWithNoSudoPasswordRequired(currentUser, password, overwriteFile = true)
|
makeUserSudoerWithoutPasswordRequired(currentUser, password, overwriteFile = true)
|
||||||
} else {
|
} else {
|
||||||
ProvResult(false, "Current user could not be determined.")
|
ProvResult(false, "Current user could not be determined.")
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import io.mockk.*
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.Prov
|
import org.domaindrivenarchitecture.provs.framework.core.Prov
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.Secret
|
import org.domaindrivenarchitecture.provs.framework.core.Secret
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.cli.createProvInstance
|
import org.domaindrivenarchitecture.provs.framework.core.cli.createProvInstance
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.cli.retrievePassword
|
import org.domaindrivenarchitecture.provs.framework.core.cli.getPasswordToConfigureSudoWithoutPassword
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.local
|
import org.domaindrivenarchitecture.provs.framework.core.local
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.processors.PrintOnlyProcessor
|
import org.domaindrivenarchitecture.provs.framework.core.processors.PrintOnlyProcessor
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.remote
|
import org.domaindrivenarchitecture.provs.framework.core.remote
|
||||||
|
@ -24,8 +24,8 @@ internal class CliTargetCommandKtTest {
|
||||||
mockkStatic(::remote)
|
mockkStatic(::remote)
|
||||||
every { remote(any(), any(), any(), any()) } returns Prov.newInstance(PrintOnlyProcessor())
|
every { remote(any(), any(), any(), any()) } returns Prov.newInstance(PrintOnlyProcessor())
|
||||||
|
|
||||||
mockkStatic(::retrievePassword)
|
mockkStatic(::getPasswordToConfigureSudoWithoutPassword)
|
||||||
every { retrievePassword(any()) } returns Secret("sec")
|
every { getPasswordToConfigureSudoWithoutPassword() } returns Secret("sec")
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterAll
|
@AfterAll
|
||||||
|
@ -34,7 +34,7 @@ internal class CliTargetCommandKtTest {
|
||||||
unmockkObject(Prov)
|
unmockkObject(Prov)
|
||||||
unmockkStatic(::local)
|
unmockkStatic(::local)
|
||||||
unmockkStatic(::remote)
|
unmockkStatic(::remote)
|
||||||
unmockkStatic(::retrievePassword)
|
unmockkStatic(::getPasswordToConfigureSudoWithoutPassword)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import org.domaindrivenarchitecture.provs.configuration.domain.TargetCliCommand
|
||||||
import org.domaindrivenarchitecture.provs.desktop.domain.*
|
import org.domaindrivenarchitecture.provs.desktop.domain.*
|
||||||
import org.domaindrivenarchitecture.provs.desktop.infrastructure.getConfig
|
import org.domaindrivenarchitecture.provs.desktop.infrastructure.getConfig
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.*
|
import org.domaindrivenarchitecture.provs.framework.core.*
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.cli.retrievePassword
|
import org.domaindrivenarchitecture.provs.framework.core.cli.getPasswordToConfigureSudoWithoutPassword
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.processors.DummyProcessor
|
import org.domaindrivenarchitecture.provs.framework.core.processors.DummyProcessor
|
||||||
import org.domaindrivenarchitecture.provs.test.setRootLoggingLevel
|
import org.domaindrivenarchitecture.provs.test.setRootLoggingLevel
|
||||||
import org.junit.jupiter.api.AfterAll
|
import org.junit.jupiter.api.AfterAll
|
||||||
|
@ -52,8 +52,8 @@ internal class ApplicationKtTest {
|
||||||
cmd = "mocked command"
|
cmd = "mocked command"
|
||||||
)
|
)
|
||||||
|
|
||||||
mockkStatic(::retrievePassword)
|
mockkStatic(::getPasswordToConfigureSudoWithoutPassword)
|
||||||
every { retrievePassword(any()) } returns Secret("sec")
|
every { getPasswordToConfigureSudoWithoutPassword() } returns Secret("sec")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("unused") // false positive
|
@Suppress("unused") // false positive
|
||||||
|
@ -65,7 +65,7 @@ internal class ApplicationKtTest {
|
||||||
unmockkStatic(::remote)
|
unmockkStatic(::remote)
|
||||||
unmockkStatic(::getConfig)
|
unmockkStatic(::getConfig)
|
||||||
unmockkStatic(Prov::provisionDesktop)
|
unmockkStatic(Prov::provisionDesktop)
|
||||||
unmockkStatic(::retrievePassword)
|
unmockkStatic(::getPasswordToConfigureSudoWithoutPassword)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue