Skip to content

Commit

Permalink
New system connection add test
Browse files Browse the repository at this point in the history
The e2e test introduced by this PR verifies that
the command `system connection add` against an
SSH server parses and updates correctly the local
`known_hosts` file.

Depends on containers/common#2212
Fixes containers#23575

Signed-off-by: Mario Loriedo <[email protected]>
  • Loading branch information
l0rd committed Oct 22, 2024
1 parent 2155438 commit ff087db
Show file tree
Hide file tree
Showing 11 changed files with 1,073 additions and 113 deletions.
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ require (
github.com/sigstore/fulcio v1.6.4 // indirect
github.com/sigstore/rekor v1.3.6 // indirect
github.com/sigstore/sigstore v1.8.9 // indirect
github.com/skeema/knownhosts v1.3.0 // indirect
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6 // indirect
github.com/sylabs/sif/v2 v2.19.1 // indirect
Expand Down Expand Up @@ -226,3 +227,5 @@ require (
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
tags.cncf.io/container-device-interface/specs-go v0.8.0 // indirect
)

replace github.com/containers/common v0.60.1-0.20241018183244-7e6f2b4d6de7 => github.com/l0rd/containers-common v0.0.0-20241022154342-ca63ba0b720f
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,6 @@ github.com/containernetworking/plugins v1.5.1 h1:T5ji+LPYjjgW0QM+KyrigZbLsZ8jaX+
github.com/containernetworking/plugins v1.5.1/go.mod h1:MIQfgMayGuHYs0XdNudf31cLLAC+i242hNm6KuDGqCM=
github.com/containers/buildah v1.37.1-0.20241018144937-2551c8f3d110 h1:YcrjUM1CwDTEnaPHgpVmjid/R3zAVXRRHcgknQsajlI=
github.com/containers/buildah v1.37.1-0.20241018144937-2551c8f3d110/go.mod h1:SVyERMThmMXGTdle/9MdRuX2Ae7eVY9qDVartYXIx7E=
github.com/containers/common v0.60.1-0.20241018183244-7e6f2b4d6de7 h1:EFzq3sjwy0vBr9RoZPzTbtoGZR4hoZsmgxuIs5Uc5FA=
github.com/containers/common v0.60.1-0.20241018183244-7e6f2b4d6de7/go.mod h1:T8vpUWd7AspK7CMELf/c+NCZB6bKrRkLriRCspdFGyQ=
github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg=
github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
github.com/containers/gvisor-tap-vsock v0.7.5 h1:bTy4u3DOmmUPwurL6me2rsgfypAFDhyeJleUcQmBR/E=
Expand Down Expand Up @@ -322,6 +320,8 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/l0rd/containers-common v0.0.0-20241022154342-ca63ba0b720f h1:/b+0pAwLqPPsNMjIkJmVzCNjQI4vVrwH5QOL/u8mpJE=
github.com/l0rd/containers-common v0.0.0-20241022154342-ca63ba0b720f/go.mod h1:YJ/JrTD8ZjvR5FjHfM/7HjwN6O5zjO/oRTLohw1mwtg=
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec h1:2tTW6cDth2TSgRbAhD7yjZzTQmcN25sDRPEeinR51yQ=
Expand Down Expand Up @@ -462,6 +462,8 @@ github.com/sigstore/sigstore v1.8.9 h1:NiUZIVWywgYuVTxXmRoTT4O4QAGiTEKup4N1wdxFa
github.com/sigstore/sigstore v1.8.9/go.mod h1:d9ZAbNDs8JJfxJrYmulaTazU3Pwr8uLL9+mii4BNR3w=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY=
github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M=
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
Expand Down
140 changes: 130 additions & 10 deletions test/e2e/system_connection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package integration

import (
"bytes"
"context"
"fmt"
"net"
Expand Down Expand Up @@ -437,16 +438,6 @@ qe ssh://[email protected]:2222/run/podman/podman.sock ~/.ssh/id_rsa false true
u, err := user.Current()
Expect(err).ShouldNot(HaveOccurred())

// Ensure that the remote end uses our built podman
if os.Getenv("PODMAN_BINARY") == "" {
err = os.Setenv("PODMAN_BINARY", podmanTest.PodmanBinary)
Expect(err).ShouldNot(HaveOccurred())

defer func() {
os.Unsetenv("PODMAN_BINARY")
}()
}

cmd := exec.Command(podmanTest.RemotePodmanBinary,
"system", "connection", "add",
"--default",
Expand Down Expand Up @@ -488,5 +479,134 @@ qe ssh://[email protected]:2222/run/podman/podman.sock ~/.ssh/id_rsa false true
Expect(lsSession).Should(Exit(0))
Expect(string(lsSession.Out.Contents())).To(Equal("QA " + uri.String() + " " + filepath.Join(u.HomeDir, ".ssh", "id_ed25519") + " true true\n"))
})

It("add ssh:// with known_hosts file", func() {
u, err := user.Current()
Expect(err).ShouldNot(HaveOccurred())

currentSSHServerHostname := "localhost"
currentSSHServerFakeKey := currentSSHServerHostname + " ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGnBlHlwqleAtyzT01mLa+DXQFyxX8T0oa8odcEZ2/07"
differentSSHServerKey := "differentserver ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGnBlHlwqleAtyzT01mLa+DXQFyxX8T0oa8odcEZ2/07"

// Retrieve current SSH server first two keys
// with `ssh-keyscan localhost`
cmd := exec.Command("ssh-keyscan", currentSSHServerHostname)
session, err := Start(cmd, GinkgoWriter, GinkgoWriter)
Expect(err).ToNot(HaveOccurred(), fmt.Sprintf("ssh-keyscan %s failed to execute", currentSSHServerHostname))
Eventually(session, DefaultWaitTimeout).Should(Exit(0))
Expect(session.Out.Contents()).ShouldNot(BeEmpty())
// Even if no error occurs, ssh-keyscan writes the
// list of hosts to stderr
Expect(session.Err.Contents()).ShouldNot(BeEmpty())
serverKeys := bytes.Split(session.Out.Contents(), []byte("\n"))
Expect(len(serverKeys)).Should(BeNumerically(">=", 2), fmt.Sprintf("ssh-keyscan %s returned less then 2 keys", currentSSHServerHostname))
currentSSHServerFirstKey := string(serverKeys[0])
currentSSHServerSecondKey := string(serverKeys[1])

khTests := [] struct {
description string
initialKhKeys []string
shouldFail bool
shouldAddKey bool
} {
{
"known_host with a public key of the SSH server that matches the SSH server first key",
[]string{currentSSHServerFirstKey},
false,
false,
},
{
"known_host with a public key of the SSH server that matches SSH server second key",
[]string{currentSSHServerSecondKey},
false,
false,
},
{
"known_host with a fake public key of the SSH server that doesn't match any of the SSH server keys (should fail)",
[]string{currentSSHServerFakeKey},
true,
false,
},
{
"known_host with no public key for the SSH server (new key should be added)",
[]string{differentSSHServerKey},
false,
true,
},
{
"known_host not existing (should be created and a new key should be added)",
[]string{},
false,
true,
},
}

for _, khTest := range khTests {
GinkgoWriter.Printf("Testing with: %s\n", khTest.description)

// To use a different known_hosts file than the one
// in the user's home directory we generate a new one
// and change HOME environment variable to point to it.

// Create a temporary directory
tempHome, err := os.MkdirTemp("", "known_hosts-*")
Expect(err).ToNot(HaveOccurred())
defer os.RemoveAll(tempHome)

// Create an .ssh directory in the temporary directory
tempSSHDir := filepath.Join(tempHome, ".ssh")
err = os.Mkdir(tempSSHDir, 0700)
Expect(err).ToNot(HaveOccurred())

// Create known_hosts file if needed
khFilePath := filepath.Join(tempSSHDir, "known_hosts")
if len(khTest.initialKhKeys) > 0 {
khFile, err := os.Create(khFilePath)
Expect(err).ToNot(HaveOccurred())
defer khFile.Close()
err = os.WriteFile(khFilePath, []byte(strings.Join(khTest.initialKhKeys, "\n")), 0600)
Expect(err).ToNot(HaveOccurred())
}

// Set HOME to the temporary directory
err = os.Setenv("HOME", tempHome)
Expect(err).ToNot(HaveOccurred())
defer os.Setenv("HOME", u.HomeDir)

// Run podman system connection add
cmd := exec.Command(podmanTest.RemotePodmanBinary,
"system", "connection", "add",
"--default",
"--identity", filepath.Join(u.HomeDir, ".ssh", "id_ed25519"),
"QA",
fmt.Sprintf("ssh://%s@%s", u.Username, currentSSHServerHostname))
session, err := Start(cmd, GinkgoWriter, GinkgoWriter)
Expect(err).ToNot(HaveOccurred(), fmt.Sprintf("%q failed to execute", podmanTest.RemotePodmanBinary))
Expect(session.Out.Contents()).Should(BeEmpty())

if khTest.shouldFail {
Eventually(session, DefaultWaitTimeout).Should(Exit(125))
Expect(session.Err.Contents()).ShouldNot(BeEmpty())
} else {
Eventually(session, DefaultWaitTimeout).Should(Exit(0))
Expect(session.Err.Contents()).Should(BeEmpty())
}

// If the known_hosts file didn't exist, it should
// have been created
if len(khTest.initialKhKeys) == 0 {
Expect(khFilePath).To(BeAnExistingFile())
}

// If the known_hosts file didn't contain the SSH server
// public key it should have been added
if khTest.shouldAddKey {
khFileContent, err := os.ReadFile(khFilePath)
Expect(err).ToNot(HaveOccurred())
khLines := bytes.Split(khFileContent, []byte("\n"))
Expect(len(khLines)).To(BeNumerically(">", len(khTest.initialKhKeys)))
}
}
})
})
})
Loading

0 comments on commit ff087db

Please sign in to comment.