refactor-git-trust (#4)
Co-authored-by: Michael Jerger <michael.jerger@meissa-gmbh.de> Co-authored-by: ansgarz <ansgar.zwick@meissa.de> Reviewed-on: #4
This commit is contained in:
parent
c1267ac17e
commit
3f4d5bb4d6
13 changed files with 275 additions and 77 deletions
38
doc/dev/ADRServicesImplementationStatic.md
Normal file
38
doc/dev/ADRServicesImplementationStatic.md
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
# ADR: We implement domain services static
|
||||||
|
|
||||||
|
Domain services can be implemented either as object (and composed like done in spring / example1 ) or with extension
|
||||||
|
function and composed static (see example2).
|
||||||
|
|
||||||
|
## example1
|
||||||
|
```kotlin
|
||||||
|
class DesktopServie(val aptApi: AptApi, val prov: Prov) {
|
||||||
|
fun provisionIdeDesktop(onlyModules: List<String>? = null) {
|
||||||
|
prov.task {
|
||||||
|
if (onlyModules == null) {
|
||||||
|
aptApi.aptInstall(OPEN_VPM)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## example2
|
||||||
|
```kotlin
|
||||||
|
fun Prov.provisionIdeDesktop(onlyModules: List<String>? = null) {
|
||||||
|
if (onlyModules == null) {
|
||||||
|
aptInstall(OPEN_VPM)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Decission
|
||||||
|
|
||||||
|
We use extension function and composed static.
|
||||||
|
|
||||||
|
## Reason
|
||||||
|
|
||||||
|
1. Similar to composed objects we can easily mock `aptInstall` in tests. Both solutions are equivalent.
|
||||||
|
2. Inheritance in case of composed objects we can solve by static composition.
|
||||||
|
3. Object composition we can solve by static composition.
|
||||||
|
|
||||||
|
There is no reason left to change the current implementd pattern.
|
77
doc/dev/architecture.md
Normal file
77
doc/dev/architecture.md
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
|
||||||
|
## Initialization
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
actor user
|
||||||
|
participant app as Application
|
||||||
|
participant ds as DesktopService
|
||||||
|
participant gtr as KnownHost
|
||||||
|
participant pa as CliArgumentsParser
|
||||||
|
participant cr as DesktopConfigRepository
|
||||||
|
participant ut as CliUtils
|
||||||
|
participant su as ProvsWithSudo
|
||||||
|
|
||||||
|
user ->> app: main
|
||||||
|
activate app
|
||||||
|
app ->> pa: parseCommands
|
||||||
|
app ->> cr: getConfig(configFileName)
|
||||||
|
app ->> ut: createProvInstance(cmd.target)
|
||||||
|
app ->> su: ensureSudoWithoutPassword(cmd.target.remoteTarget()?.password)
|
||||||
|
app ->> ds: provisionDesktopCommand(cmd, config)
|
||||||
|
activate ds
|
||||||
|
ds ->> gtr: values()
|
||||||
|
gtr -->> ds: List(KnownHost)
|
||||||
|
deactivate ds
|
||||||
|
deactivate app
|
||||||
|
```
|
||||||
|
|
||||||
|
## Domain
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
classDiagram
|
||||||
|
|
||||||
|
namespace configuration {
|
||||||
|
|
||||||
|
class TargetCliCommand {
|
||||||
|
val target: String,
|
||||||
|
val passwordInteractive: Boolean = false
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConfigFileName {
|
||||||
|
fileName: String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace desktop {
|
||||||
|
|
||||||
|
class DesktopCliCommand {
|
||||||
|
}
|
||||||
|
|
||||||
|
class DesktopConfig {
|
||||||
|
val ssh: SshKeyPairSource? = null,
|
||||||
|
val gpg: KeyPairSource? = null,
|
||||||
|
val gitUserName: String? = null,
|
||||||
|
val gitEmail: String? = null,
|
||||||
|
}
|
||||||
|
|
||||||
|
class DesktopType {
|
||||||
|
val name: String
|
||||||
|
}
|
||||||
|
class DesktopOnlyModule {
|
||||||
|
<<enum>>
|
||||||
|
FIREFOX, VERIFY
|
||||||
|
}
|
||||||
|
|
||||||
|
class KnownHost {
|
||||||
|
hostName: String,
|
||||||
|
hostKeys: List<HostKey>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DesktopCliCommand "1" *-- "1" DesktopType: type
|
||||||
|
DesktopCliCommand "1" *-- "1" TargetCliCommand: target
|
||||||
|
DesktopCliCommand "1" *-- "1" ConfigFileName: configFile
|
||||||
|
DesktopCliCommand "1" *-- "..n" DesktopOnlyModule: onlyModules
|
||||||
|
|
||||||
|
```
|
|
@ -12,6 +12,7 @@ import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.provisionKeys
|
||||||
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.whoami
|
import org.domaindrivenarchitecture.provs.framework.ubuntu.user.base.whoami
|
||||||
|
|
||||||
|
|
||||||
internal fun Prov.provisionDesktopCommand(cmd: DesktopCliCommand, conf: DesktopConfig) = task {
|
internal fun Prov.provisionDesktopCommand(cmd: DesktopCliCommand, conf: DesktopConfig) = task {
|
||||||
provisionDesktop(
|
provisionDesktop(
|
||||||
cmd.type,
|
cmd.type,
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
package org.domaindrivenarchitecture.provs.desktop.domain
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A HostKey should contain space-separated: keytype, key and (optionally) a comment
|
||||||
|
*
|
||||||
|
* See: https://man7.org/linux/man-pages/man8/sshd.8.html#SSH_KNOWN_HOSTS_FILE_FORMAT
|
||||||
|
*/
|
||||||
|
typealias HostKey = String
|
||||||
|
|
||||||
|
open class KnownHost protected constructor(val hostName: String, val hostKeys: List<HostKey>) {
|
||||||
|
companion object {
|
||||||
|
val GITHUB = KnownHost(
|
||||||
|
"github.com", listOf(
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl",
|
||||||
|
"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=",
|
||||||
|
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk=",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val GITLAB = KnownHost(
|
||||||
|
"gitlab.com", listOf(
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf",
|
||||||
|
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9",
|
||||||
|
"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY=",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
protected val values = listOf(GITHUB, GITLAB)
|
||||||
|
|
||||||
|
fun values(): List<KnownHost> {
|
||||||
|
return values
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package org.domaindrivenarchitecture.provs.desktop.domain
|
||||||
|
|
||||||
|
import org.domaindrivenarchitecture.provs.framework.core.Prov
|
||||||
|
import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.base.addKnownHost
|
||||||
|
|
||||||
|
|
||||||
|
fun Prov.addKnownHosts(knownHosts: List<KnownHost> = KnownHost.values()) = task {
|
||||||
|
for (knownHost in knownHosts) {
|
||||||
|
with(knownHost) {
|
||||||
|
addKnownHost(hostName, hostKeys, verifyKeys = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,7 +15,9 @@ fun Prov.installDevOps() = task {
|
||||||
installTerraform()
|
installTerraform()
|
||||||
installKubectlAndTools()
|
installKubectlAndTools()
|
||||||
installYq()
|
installYq()
|
||||||
|
// TODO: the can be removed
|
||||||
installAwsCredentials()
|
installAwsCredentials()
|
||||||
|
// TODO: the can be removed
|
||||||
installDevOpsFolder()
|
installDevOpsFolder()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,6 @@ package org.domaindrivenarchitecture.provs.framework.ubuntu.git.base
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.Prov
|
import org.domaindrivenarchitecture.provs.framework.core.Prov
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.ProvResult
|
import org.domaindrivenarchitecture.provs.framework.core.ProvResult
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.*
|
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.*
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.base.KNOWN_HOSTS_FILE
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.base.trustHost
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -41,25 +38,3 @@ fun Prov.gitClone(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun Prov.trustGithub() = task {
|
|
||||||
// current fingerprints from https://docs.github.com/en/github/authenticating-to-github/githubs-ssh-key-fingerprints
|
|
||||||
val fingerprints = setOf(
|
|
||||||
"SHA256:uNiVztksCsDhcc0u9e8BujQXVUpKZIDTMczCvj3tD2s github.com", // (RSA)
|
|
||||||
"SHA256:p2QAMXNIC1TJYWeIOttrVc98/R1BUFWu3/LiyKgUfQM github.com", // (ECDSA)
|
|
||||||
"SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU github.com" // (Ed25519)
|
|
||||||
)
|
|
||||||
trustHost("github.com", fingerprints)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun Prov.trustGitlab() = task {
|
|
||||||
// entries for known_hosts from https://docs.gitlab.com/ee/user/gitlab_com/
|
|
||||||
val gitlabFingerprints = """
|
|
||||||
gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf
|
|
||||||
gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9
|
|
||||||
gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY=
|
|
||||||
""".trimIndent()
|
|
||||||
addTextToFile("\n" + gitlabFingerprints + "\n", File(KNOWN_HOSTS_FILE))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,9 @@ package org.domaindrivenarchitecture.provs.framework.ubuntu.keys.base
|
||||||
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.Prov
|
import org.domaindrivenarchitecture.provs.framework.core.Prov
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.ProvResult
|
import org.domaindrivenarchitecture.provs.framework.core.ProvResult
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.echoCommandForText
|
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.*
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.checkFile
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.createDir
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.createFile
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.createSecretFile
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.SshKeyPair
|
import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.SshKeyPair
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
|
||||||
const val KNOWN_HOSTS_FILE = "~/.ssh/known_hosts"
|
const val KNOWN_HOSTS_FILE = "~/.ssh/known_hosts"
|
||||||
|
@ -34,61 +31,39 @@ fun Prov.isHostKnown(hostOrIp: String) : Boolean {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds ssh keys for specified host (which also can be an ip-address) to ssh-file "known_hosts"
|
* Adds ssh keys for specified host (which also can be an ip-address) to ssh-file "known_hosts"
|
||||||
* Either add the specified rsaFingerprints or - if null - add automatically retrieved keys.
|
* Either add the specified keys or - if null - add keys automatically retrieved.
|
||||||
* Note: adding keys automatically is vulnerable to a man-in-the-middle attack, thus considered insecure and not recommended.
|
* Note: adding keys automatically is vulnerable to a man-in-the-middle attack, thus considered insecure and not recommended.
|
||||||
*/
|
*/
|
||||||
fun Prov.trustHost(host: String, fingerprintsOfKeysToBeAdded: Set<String>?) = taskWithResult {
|
fun Prov.addKnownHost(host: String, keysToBeAdded: List<String>?, verifyKeys: Boolean = false) = task {
|
||||||
if (isHostKnown(host)) {
|
|
||||||
return@taskWithResult ProvResult(true, out = "Host already known")
|
|
||||||
}
|
|
||||||
if (!checkFile(KNOWN_HOSTS_FILE)) {
|
if (!checkFile(KNOWN_HOSTS_FILE)) {
|
||||||
createDir(".ssh")
|
createDir(".ssh")
|
||||||
createFile(KNOWN_HOSTS_FILE, null)
|
createFile(KNOWN_HOSTS_FILE, null)
|
||||||
}
|
}
|
||||||
if (fingerprintsOfKeysToBeAdded == null) {
|
if (keysToBeAdded == null) {
|
||||||
// auto add keys
|
// auto add keys
|
||||||
cmd("ssh-keyscan $host >> $KNOWN_HOSTS_FILE")
|
cmd("ssh-keyscan $host >> $KNOWN_HOSTS_FILE")
|
||||||
} else {
|
} else {
|
||||||
// logic based on https://serverfault.com/questions/447028/non-interactive-git-clone-ssh-fingerprint-prompt
|
for (key in keysToBeAdded) {
|
||||||
val actualKeys = findSshKeys(host)
|
if (!verifyKeys) {
|
||||||
if (actualKeys == null || actualKeys.size == 0) {
|
addTextToFile("\n$host $key\n", File(KNOWN_HOSTS_FILE))
|
||||||
return@taskWithResult ProvResult(false, out = "No valid keys found for host: $host")
|
} else {
|
||||||
}
|
val validKeys = getSshKeys(host)
|
||||||
val actualFingerprints = getFingerprintsForKeys(actualKeys)
|
if (validKeys?.contains(key) == true) {
|
||||||
for (fingerprintToBeAdded in fingerprintsOfKeysToBeAdded) {
|
addTextToFile("\n$host $key\n", File(KNOWN_HOSTS_FILE))
|
||||||
var indexOfKeyFound = -1
|
} else {
|
||||||
|
addResultToEval(ProvResult(false, err = "The following key of host [$host] could not be verified successfully: " + key))
|
||||||
// search for fingerprint in actual fingerprints
|
|
||||||
for ((i, actualFingerprint) in actualFingerprints.withIndex()) {
|
|
||||||
if (actualFingerprint.contains(fingerprintToBeAdded)) {
|
|
||||||
indexOfKeyFound = i
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (indexOfKeyFound == -1) {
|
|
||||||
return@taskWithResult ProvResult(
|
|
||||||
false,
|
|
||||||
err = "Fingerprint ($fingerprintToBeAdded) could not be found in actual fingerprints: $actualFingerprints"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
cmd(echoCommandForText(actualKeys.get(indexOfKeyFound) + "\n") + " >> $KNOWN_HOSTS_FILE")
|
|
||||||
}
|
|
||||||
ProvResult(true)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of valid ssh keys for the given host (host can also be an ip address)
|
* Returns a list of valid ssh keys for the given host (host can also be an ip address), keys are returned as keytype and key BUT WITHOUT the host name
|
||||||
*/
|
*/
|
||||||
private fun Prov.findSshKeys(host: String): List<String>? {
|
private fun Prov.getSshKeys(host: String, keytype: String? = null): List<String>? {
|
||||||
return cmd("ssh-keyscan $host 2>/dev/null").out?.split("\n")?.filter { x -> "" != x }
|
val keytypeOption = keytype?.let { " -t $keytype " } ?: ""
|
||||||
}
|
val output = cmd("ssh-keyscan $keytypeOption $host 2>/dev/null").out?.trim()
|
||||||
|
return output?.split("\n")?.filter { x -> "" != x }?.map { x -> x.substringAfter(" ") }
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of fingerprints of the given sshKeys; the returning list has same size and order as the specified list of sshKeys
|
|
||||||
*/
|
|
||||||
private fun Prov.getFingerprintsForKeys(sshKeys: List<String>): List<String> {
|
|
||||||
return sshKeys.map { x -> cmd("echo \"$x\" | ssh-keygen -lf -").out ?: "" }
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ import org.junit.jupiter.api.AfterAll
|
||||||
import org.junit.jupiter.api.BeforeAll
|
import org.junit.jupiter.api.BeforeAll
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
internal class CliTargetCommandKtTest {
|
internal class TargetCliCommandKtTest {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
package org.domaindrivenarchitecture.provs.desktop.domain
|
||||||
|
|
||||||
|
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.deleteFile
|
||||||
|
import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.aptInstall
|
||||||
|
import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.base.KNOWN_HOSTS_FILE
|
||||||
|
import org.domaindrivenarchitecture.provs.test.defaultTestContainer
|
||||||
|
import org.domaindrivenarchitecture.provs.test.tags.ContainerTest
|
||||||
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
|
import org.junit.jupiter.api.Assertions.assertTrue
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
|
||||||
|
class KnownHostTest {
|
||||||
|
|
||||||
|
@ContainerTest
|
||||||
|
fun defaultKnownHosts() {
|
||||||
|
// given
|
||||||
|
val prov = defaultTestContainer()
|
||||||
|
prov.task {
|
||||||
|
aptInstall("ssh")
|
||||||
|
deleteFile(KNOWN_HOSTS_FILE)
|
||||||
|
}
|
||||||
|
|
||||||
|
// when
|
||||||
|
val res = prov.addKnownHosts()
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertTrue(res.success)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Subclass of KnownHost for test knownHostSubclass_includes_additional_host
|
||||||
|
class KnownHostsSubclass(hostName: String, hostKeys: List<HostKey>): KnownHost(hostName, hostKeys) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val ANOTHER_HOST = KnownHostsSubclass("anotherhost.com", listOf("key1"))
|
||||||
|
|
||||||
|
fun values(): List<KnownHost> {
|
||||||
|
return values + ANOTHER_HOST
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun knownHostSubclass_includes_additional_host() {
|
||||||
|
// when
|
||||||
|
val hosts = KnownHostsSubclass.values()
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertTrue(hosts.size > 1)
|
||||||
|
assertEquals("key1", hosts.last().hostKeys[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.domaindrivenarchitecture.provs.framework.ubuntu.git.base
|
package org.domaindrivenarchitecture.provs.framework.ubuntu.git.base
|
||||||
|
|
||||||
|
import org.domaindrivenarchitecture.provs.desktop.domain.addKnownHosts
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.checkDir
|
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.checkDir
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.aptInstall
|
import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.aptInstall
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.base.isHostKnown
|
import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.base.isHostKnown
|
||||||
|
@ -18,12 +19,10 @@ internal class GitKtTest {
|
||||||
a.aptInstall("openssh-client")
|
a.aptInstall("openssh-client")
|
||||||
|
|
||||||
// when
|
// when
|
||||||
val res = a.trustGithub()
|
val res = a.addKnownHosts()
|
||||||
val res2 = a.trustGitlab()
|
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertTrue(res.success)
|
assertTrue(res.success)
|
||||||
assertTrue(res2.success)
|
|
||||||
|
|
||||||
assertTrue(a.isHostKnown("github.com"), "github.com does not seem to be a known host")
|
assertTrue(a.isHostKnown("github.com"), "github.com does not seem to be a known host")
|
||||||
assertTrue(a.isHostKnown("gitlab.com"), "gitlab.com does not seem to be a known host")
|
assertTrue(a.isHostKnown("gitlab.com"), "gitlab.com does not seem to be a known host")
|
||||||
|
@ -37,7 +36,7 @@ internal class GitKtTest {
|
||||||
prov.aptInstall("git")
|
prov.aptInstall("git")
|
||||||
|
|
||||||
// when
|
// when
|
||||||
prov.trustGithub()
|
prov.addKnownHosts()
|
||||||
val res1 = prov.gitClone("https://gitlab.com/domaindrivenarchitecture/not a valid basename.git", "~/")
|
val res1 = prov.gitClone("https://gitlab.com/domaindrivenarchitecture/not a valid basename.git", "~/")
|
||||||
val res2 = prov.gitClone(repo)
|
val res2 = prov.gitClone(repo)
|
||||||
val res3 = prov.gitClone(repo, pullIfExisting = false)
|
val res3 = prov.gitClone(repo, pullIfExisting = false)
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
package org.domaindrivenarchitecture.provs.framework.ubuntu.keys.base
|
package org.domaindrivenarchitecture.provs.framework.ubuntu.keys.base
|
||||||
|
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.Secret
|
import org.domaindrivenarchitecture.provs.framework.core.Secret
|
||||||
|
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.deleteFile
|
||||||
|
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.fileContainsText
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.fileContent
|
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.fileContent
|
||||||
|
import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.aptInstall
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.*
|
import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.*
|
||||||
import org.domaindrivenarchitecture.provs.test.defaultTestContainer
|
import org.domaindrivenarchitecture.provs.test.defaultTestContainer
|
||||||
import org.domaindrivenarchitecture.provs.test.tags.ContainerTest
|
import org.domaindrivenarchitecture.provs.test.tags.ContainerTest
|
||||||
import org.junit.jupiter.api.Assertions.assertEquals
|
import org.junit.jupiter.api.Assertions.*
|
||||||
import org.junit.jupiter.api.Assertions.assertTrue
|
|
||||||
|
|
||||||
internal class SshKtTest {
|
internal class SshKtTest {
|
||||||
|
|
||||||
@ContainerTest
|
@ContainerTest
|
||||||
fun configureSshKeys_for_ssh_type_rsa() {
|
fun configureSshKeys_for_ssh_type_rsa() {
|
||||||
// given
|
// given
|
||||||
|
@ -45,4 +46,32 @@ internal class SshKtTest {
|
||||||
val privateSshKeyFileContent = prov.fileContent("~/.ssh/id_ed25519")
|
val privateSshKeyFileContent = prov.fileContent("~/.ssh/id_ed25519")
|
||||||
assertEquals(privateED25519SnakeOilKey() + "\n", privateSshKeyFileContent)
|
assertEquals(privateED25519SnakeOilKey() + "\n", privateSshKeyFileContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ContainerTest
|
||||||
|
fun addKnownHost() {
|
||||||
|
// given
|
||||||
|
val prov = defaultTestContainer()
|
||||||
|
prov.task {
|
||||||
|
aptInstall("ssh")
|
||||||
|
deleteFile(KNOWN_HOSTS_FILE)
|
||||||
|
}
|
||||||
|
|
||||||
|
// when
|
||||||
|
val res = prov.addKnownHost("github.com", listOf("dummyProtocol dummyKey", "dummyProtocol2 dummyKey2", ))
|
||||||
|
val res2 = prov.addKnownHost("github.com", listOf("dummyProtocol dummyKey", "dummyProtocol2 dummyKey2", ))
|
||||||
|
val res3 = prov.addKnownHost("github.com", listOf("ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl", ), verifyKeys = true)
|
||||||
|
val res4 = prov.addKnownHost("github.com", listOf("ssh-ed25519 AAAAC3Nzalwrongkey!!!", ), verifyKeys = true)
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertTrue(res.success)
|
||||||
|
assertTrue(prov.fileContainsText(KNOWN_HOSTS_FILE, "github.com dummyProtocol dummyKey"))
|
||||||
|
assertTrue(prov.fileContainsText(KNOWN_HOSTS_FILE, "github.com dummyProtocol2 dummyKey2"))
|
||||||
|
|
||||||
|
assertTrue(res2.success)
|
||||||
|
val keyCount = prov.cmd("grep -o -i dummyKey2 $KNOWN_HOSTS_FILE | wc -l").out?.trim()
|
||||||
|
assertEquals("1", keyCount)
|
||||||
|
|
||||||
|
assertTrue(res3.success)
|
||||||
|
assertFalse(res4.success)
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue