Skip to content

Conversation

@pau-hedgehog
Copy link
Contributor

@pau-hedgehog pau-hedgehog commented Oct 28, 2025

Mainly to prove if we need full VLAB or not for these level of testing and to kick off discussion after brief discussion with @edipascale

@pau-hedgehog pau-hedgehog self-assigned this Oct 28, 2025
@github-actions
Copy link

🚀 Temp artifacts published: v0-577e0db89 🚀

Signed-off-by: Pau Capdevila <pau@githedgehog.com>
@pau-hedgehog pau-hedgehog force-pushed the pau/gnmi_integration_tests branch from 577e0db to 38a9d36 Compare October 28, 2025 12:28
@pau-hedgehog
Copy link
Contributor Author

pau-hedgehog commented Oct 28, 2025

Let's discuss if this is useful or not. Didn't proceed further as per @Frostman indication. So far it's much faster than a VLAB:

pau@pau-TP-P14s:~/fabric$ just test-agent-gnmi-vs
Building agent binary for integration tests...
GOOS=linux GOARCH=amd64 go build --tags containers_image_openpgp,containers_image_storage_stub -ldflags="-w -s -X go.githedgehog.com/fabric/pkg/version.Version=v0.92.0-11-g38a9d36a" -o ./bin/agent ./cmd/agent
Agent binary built: ./bin/agent
cd test/integration/agent-gnmi && go test -v -timeout 30m -target=vs -agent-binary=../../../bin/agent -cache-dir=./images  ./...
time=2025-10-28T13:28:59.746+01:00 level=INFO msg="Setting up SONiC VS for integration tests" cache_dir=./images agent_binary=../../../bin/agent
time=2025-10-28T13:28:59.746+01:00 level=INFO msg="Building agent binary using justfile..."
Building agent binary for integration tests...
GOOS=linux GOARCH=amd64 go build --tags containers_image_openpgp,containers_image_storage_stub -ldflags="-w -s -X go.githedgehog.com/fabric/pkg/version.Version=v0.92.0-11-g38a9d36a" -o ./bin/agent ./cmd/agent
Agent binary built: ./bin/agent
time=2025-10-28T13:29:00.068+01:00 level=INFO msg="Agent binary built successfully" path=../../../bin/agent
time=2025-10-28T13:29:00.068+01:00 level=INFO msg="Starting SONiC VS" name=sonic-vs-test memory=4096M cpus=4 ssh_port=2222 gnmi_port=8080
time=2025-10-28T13:29:00.068+01:00 level=INFO msg="SONiC VS started" name=sonic-vs-test pid=114284
time=2025-10-28T13:29:00.068+01:00 level=INFO msg="Waiting for SONiC VS to boot and be ready..."
time=2025-10-28T13:29:00.068+01:00 level=INFO msg="Waiting for SONiC VS to be ready" name=sonic-vs-test timeout=5m0s
time=2025-10-28T13:29:11.839+01:00 level=INFO msg="SONiC VS is ready" name=sonic-vs-test attempts=1
time=2025-10-28T13:29:11.839+01:00 level=INFO msg="SONiC VS is ready" ssh=localhost:2222 gnmi=localhost:8080
time=2025-10-28T13:29:11.839+01:00 level=INFO msg="Preparing test environment..."
time=2025-10-28T13:29:11.839+01:00 level=INFO msg="Preparing SONiC VM test environment"
time=2025-10-28T13:29:14.942+01:00 level=INFO msg="Test environment prepared successfully"
time=2025-10-28T13:29:14.942+01:00 level=INFO msg="Ensuring clean slate - uninstalling any existing agent..."
time=2025-10-28T13:29:14.942+01:00 level=INFO msg="Uninstalling Hedgehog agent from SONiC VM"
time=2025-10-28T13:29:19.165+01:00 level=INFO msg="Agent successfully uninstalled from SONiC VM"
time=2025-10-28T13:29:19.165+01:00 level=INFO msg="Installing agent on SONiC VS..."
time=2025-10-28T13:29:19.165+01:00 level=INFO msg="Installing Hedgehog agent on SONiC VM" binary=../../../bin/agent
time=2025-10-28T13:29:36.970+01:00 level=INFO msg="Agent successfully installed and started on SONiC VM"
time=2025-10-28T13:29:37.802+01:00 level=INFO msg="Agent status" status="installed, running\nroot        9449 36.0  4.9 1458788 181772 ?      Ssl  12:29   0:00 /opt/hedgehog/bin/agent start"
time=2025-10-28T13:29:37.802+01:00 level=INFO msg="Test environment ready - running tests..."
=== RUN   TestVMBoots
    boot_test.go:27: VM is running
    boot_test.go:28: SSH address: localhost:2222
    boot_test.go:29: gNMI address: localhost:8080
    boot_test.go:30: Serial log: images/serial.log
--- PASS: TestVMBoots (0.00s)
=== RUN   TestSSHConnectivity
    boot_test.go:47: SSH connection successful
--- PASS: TestSSHConnectivity (0.17s)
PASS
time=2025-10-28T13:29:37.976+01:00 level=INFO msg="Cleaning up - uninstalling agent..."
time=2025-10-28T13:29:37.976+01:00 level=INFO msg="Uninstalling Hedgehog agent from SONiC VM"
time=2025-10-28T13:29:42.401+01:00 level=INFO msg="Agent successfully uninstalled from SONiC VM"
time=2025-10-28T13:29:42.401+01:00 level=INFO msg="Stopping SONiC VS..."
time=2025-10-28T13:29:42.401+01:00 level=INFO msg="Stopping SONiC VS" name=sonic-vs-test
time=2025-10-28T13:29:42.439+01:00 level=WARN msg="VM exited with error" name=sonic-vs-test err="waitid: no child processes"
time=2025-10-28T13:29:42.439+01:00 level=INFO msg="SONiC VS stopped" name=sonic-vs-test
ok  	go.githedgehog.com/fabric/test/integration/agent-gnmi	42.696s

Auth: []ssh.AuthMethod{
ssh.PublicKeys(signer),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),

Check failure

Code scanning / CodeQL

Use of insecure HostKeyCallback implementation High test

Configuring SSH ClientConfig with insecure HostKeyCallback implementation from
this source
.

Copilot Autofix

AI about 1 month ago

To fix the insecure host key verification, the HostKeyCallback field should be configured to validate the remote host's public key(s) against a local allow-list. The most common approach is to load the expected public key(s) for the host—either from a file (known_hosts or a dedicated public key file) or a configuration variable—and then use ssh.FixedHostKey (if only one key) or a custom callback for multiple keys. Since this code only configures a single host at a time and no allow-list logic is provided, the minimal approach is to accept a path to the host's public key as an additional argument (for production) or load it from a well-known location. The fix involves:

  1. Adding a -hostkey flag (or hardcoding a path) pointing to the expected/allowed host public key file.
  2. Loading that public key from the file at startup.
  3. Changing the HostKeyCallback from ssh.InsecureIgnoreHostKey() to ssh.FixedHostKey(publicKey).
  4. Adding the necessary imports (ioutil or os, if not already present).
  5. Handling public key file read/parse errors gracefully.

All edits are confined to test/integration/agent-gnmi/cmd/agent-ctl/main.go in the code you have provided, specifically in the region of SSH config creation and variable definitions.


Suggested changeset 1
test/integration/agent-gnmi/cmd/agent-ctl/main.go

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/test/integration/agent-gnmi/cmd/agent-ctl/main.go b/test/integration/agent-gnmi/cmd/agent-ctl/main.go
--- a/test/integration/agent-gnmi/cmd/agent-ctl/main.go
+++ b/test/integration/agent-gnmi/cmd/agent-ctl/main.go
@@ -20,6 +20,7 @@
 	sshAddr  = flag.String("ssh", "localhost:2222", "SSH address of SONiC VM")
 	username = flag.String("user", "admin", "SSH username")
 	sshKey   = flag.String("key", "./sshkey", "Path to SSH private key")
+	hostKey  = flag.String("hostkey", "./hostkey.pub", "Path to SSH host public key (agent VM)")
 	binary   = flag.String("binary", "../../../bin/agent", "Path to agent binary (install only)")
 	verbose  = flag.Bool("v", false, "Verbose logging")
 )
@@ -69,13 +70,28 @@
 		os.Exit(1)
 	}
 
+	// Load SSH host public key
+	hostKeyData, err := os.ReadFile(*hostKey)
+	if err != nil {
+		slog.Error("Failed to read SSH host public key", "path", *hostKey, "err", err)
+		fmt.Fprintf(os.Stderr, "\nERROR: SSH host public key not found at %s\n", *hostKey)
+		fmt.Fprintf(os.Stderr, "Specify the path to your SSH host public key with -hostkey\n")
+		os.Exit(1)
+	}
+	hostPublicKey, err := ssh.ParsePublicKey(hostKeyData)
+	if err != nil {
+		slog.Error("Failed to parse SSH host public key", "err", err)
+		fmt.Fprintf(os.Stderr, "\nERROR: Invalid SSH host public key\n")
+		os.Exit(1)
+	}
+
 	// Create SSH config
 	sshConfig := &ssh.ClientConfig{
 		User: *username,
 		Auth: []ssh.AuthMethod{
 			ssh.PublicKeys(signer),
 		},
-		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
+		HostKeyCallback: ssh.FixedHostKey(hostPublicKey),
 		Timeout:         10 * time.Second,
 	}
 
EOF
@@ -20,6 +20,7 @@
sshAddr = flag.String("ssh", "localhost:2222", "SSH address of SONiC VM")
username = flag.String("user", "admin", "SSH username")
sshKey = flag.String("key", "./sshkey", "Path to SSH private key")
hostKey = flag.String("hostkey", "./hostkey.pub", "Path to SSH host public key (agent VM)")
binary = flag.String("binary", "../../../bin/agent", "Path to agent binary (install only)")
verbose = flag.Bool("v", false, "Verbose logging")
)
@@ -69,13 +70,28 @@
os.Exit(1)
}

// Load SSH host public key
hostKeyData, err := os.ReadFile(*hostKey)
if err != nil {
slog.Error("Failed to read SSH host public key", "path", *hostKey, "err", err)
fmt.Fprintf(os.Stderr, "\nERROR: SSH host public key not found at %s\n", *hostKey)
fmt.Fprintf(os.Stderr, "Specify the path to your SSH host public key with -hostkey\n")
os.Exit(1)
}
hostPublicKey, err := ssh.ParsePublicKey(hostKeyData)
if err != nil {
slog.Error("Failed to parse SSH host public key", "err", err)
fmt.Fprintf(os.Stderr, "\nERROR: Invalid SSH host public key\n")
os.Exit(1)
}

// Create SSH config
sshConfig := &ssh.ClientConfig{
User: *username,
Auth: []ssh.AuthMethod{
ssh.PublicKeys(signer),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
HostKeyCallback: ssh.FixedHostKey(hostPublicKey),
Timeout: 10 * time.Second,
}

Copilot is powered by AI and may make mistakes. Always verify output.
Auth: []ssh.AuthMethod{
ssh.PublicKeys(signer),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),

Check failure

Code scanning / CodeQL

Use of insecure HostKeyCallback implementation High test

Configuring SSH ClientConfig with insecure HostKeyCallback implementation from
this source
.

Copilot Autofix

AI about 1 month ago

To fix this issue, the code should replace ssh.InsecureIgnoreHostKey() with a secure host key validation. The standard secure solution is to validate against an allowlist of known host keys using the ssh.FixedHostKey() callback or implement a custom callback that matches the received host key against expected values. For this situation, since it's a test/integration tool, the most straightforward secure method is to require the user to provide the expected remote host public key in a file (e.g., -hostkey <path-to-allowed-hostkey.pub> argument), then parse it and use ssh.FixedHostKey(publicKey).

Necessary code modifications:

  • Add a flag for the host public key file path (-hostkey).
  • Read and parse the host public key from the file.
  • Use ssh.FixedHostKey(publicKey) in the HostKeyCallback field.

Required import: io/ioutil or replace with os.ReadFile (since Go 1.16+, os.ReadFile suffices). Also, ensure no spurious imports.

Code edits: Add flag variable, read/parse public key, and set HostKeyCallback.


Suggested changeset 1
test/integration/agent-gnmi/cmd/agent-install/main.go

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/test/integration/agent-gnmi/cmd/agent-install/main.go b/test/integration/agent-gnmi/cmd/agent-install/main.go
--- a/test/integration/agent-gnmi/cmd/agent-install/main.go
+++ b/test/integration/agent-gnmi/cmd/agent-install/main.go
@@ -22,6 +22,7 @@
 	sshKey   = flag.String("key", "./sshkey", "Path to SSH private key")
 	binary   = flag.String("binary", "../../../bin/agent", "Path to agent binary")
 	verbose  = flag.Bool("v", false, "Verbose logging")
+	hostKeyPath = flag.String("hostkey", "./hostkey.pub", "Path to allowed SSH host public key")
 )
 
 func main() {
@@ -62,13 +63,29 @@
 		os.Exit(1)
 	}
 
+	// Load allowed host public key
+	hostKeyData, err := os.ReadFile(*hostKeyPath)
+	if err != nil {
+		slog.Error("Failed to read SSH host public key", "path", *hostKeyPath, "err", err)
+		fmt.Fprintf(os.Stderr, "\nERROR: SSH host public key not found at %s\n", *hostKeyPath)
+		fmt.Fprintf(os.Stderr, "\nSpecify the path to the allowed host public key with -hostkey\n")
+		os.Exit(1)
+	}
+
+	hostPublicKey, err := ssh.ParsePublicKey(hostKeyData)
+	if err != nil {
+		slog.Error("Failed to parse SSH host public key", "err", err)
+		fmt.Fprintf(os.Stderr, "\nERROR: Invalid SSH host public key\n")
+		os.Exit(1)
+	}
+
 	// Create SSH config
 	sshConfig := &ssh.ClientConfig{
 		User: *username,
 		Auth: []ssh.AuthMethod{
 			ssh.PublicKeys(signer),
 		},
-		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
+		HostKeyCallback: ssh.FixedHostKey(hostPublicKey),
 		Timeout:         10 * time.Second,
 	}
 
EOF
@@ -22,6 +22,7 @@
sshKey = flag.String("key", "./sshkey", "Path to SSH private key")
binary = flag.String("binary", "../../../bin/agent", "Path to agent binary")
verbose = flag.Bool("v", false, "Verbose logging")
hostKeyPath = flag.String("hostkey", "./hostkey.pub", "Path to allowed SSH host public key")
)

func main() {
@@ -62,13 +63,29 @@
os.Exit(1)
}

// Load allowed host public key
hostKeyData, err := os.ReadFile(*hostKeyPath)
if err != nil {
slog.Error("Failed to read SSH host public key", "path", *hostKeyPath, "err", err)
fmt.Fprintf(os.Stderr, "\nERROR: SSH host public key not found at %s\n", *hostKeyPath)
fmt.Fprintf(os.Stderr, "\nSpecify the path to the allowed host public key with -hostkey\n")
os.Exit(1)
}

hostPublicKey, err := ssh.ParsePublicKey(hostKeyData)
if err != nil {
slog.Error("Failed to parse SSH host public key", "err", err)
fmt.Fprintf(os.Stderr, "\nERROR: Invalid SSH host public key\n")
os.Exit(1)
}

// Create SSH config
sshConfig := &ssh.ClientConfig{
User: *username,
Auth: []ssh.AuthMethod{
ssh.PublicKeys(signer),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
HostKeyCallback: ssh.FixedHostKey(hostPublicKey),
Timeout: 10 * time.Second,
}

Copilot is powered by AI and may make mistakes. Always verify output.
Auth: []ssh.AuthMethod{
ssh.PublicKeys(signer),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),

Check failure

Code scanning / CodeQL

Use of insecure HostKeyCallback implementation High test

Configuring SSH ClientConfig with insecure HostKeyCallback implementation from
this source
.

Copilot Autofix

AI about 1 month ago

To secure the SSH client connection, we need to properly verify the server’s host key instead of accepting any key using ssh.InsecureIgnoreHostKey. A secure strategy is to predefine an allow-list of trusted host public keys and only accept connections from servers presenting one of those keys. The simplest form uses ssh.FixedHostKey(publicKey) for a single known host, or a custom callback for multiple allowed keys.

Specifically, in file test/integration/agent-gnmi/cmd/agent-uninstall/main.go, replace the initialization of the HostKeyCallback field on line 61. First, load the public host key from a .pub file (the known host’s public key), then set HostKeyCallback to ssh.FixedHostKey(publicKey). This requires reading and parsing the public key immediately before assigning to ssh.ClientConfig. Also, import the io/ioutil package (needed for loading the public key for Go <1.16, but in this context we can use os.ReadFile). If we use os.ReadFile, no import changes are necessary.

Assume the public host key path is supplied as an argument (e.g., add a -hostkey flag) or hard-code a well-known path (e.g., "./ssh_hostkey.pub"), as only code in the snippet may be changed. The ideal solution is to add a hostKeyPath flag, read it, parse the public key, and use it for HostKeyCallback.

Suggested changeset 1
test/integration/agent-gnmi/cmd/agent-uninstall/main.go

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/test/integration/agent-gnmi/cmd/agent-uninstall/main.go b/test/integration/agent-gnmi/cmd/agent-uninstall/main.go
--- a/test/integration/agent-gnmi/cmd/agent-uninstall/main.go
+++ b/test/integration/agent-gnmi/cmd/agent-uninstall/main.go
@@ -20,6 +20,7 @@
 	sshAddr    = flag.String("ssh", "localhost:2222", "SSH address of SONiC VM")
 	username   = flag.String("user", "admin", "SSH username")
 	sshKey     = flag.String("key", "./sshkey", "Path to SSH private key")
+	hostKey    = flag.String("hostkey", "./ssh_hostkey.pub", "Path to SSH host public key")
 	showStatus = flag.Bool("status", false, "Show agent status instead of uninstalling")
 	verbose    = flag.Bool("v", false, "Verbose logging")
 )
@@ -52,13 +53,29 @@
 		os.Exit(1)
 	}
 
+	// Load SSH host public key
+	hostKeyData, err := os.ReadFile(*hostKey)
+	if err != nil {
+		slog.Error("Failed to read SSH host public key", "path", *hostKey, "err", err)
+		fmt.Fprintf(os.Stderr, "\nERROR: SSH host public key not found at %s\n", *hostKey)
+		fmt.Fprintf(os.Stderr, "\nSpecify the path to your SSH host public key with -hostkey\n")
+		os.Exit(1)
+	}
+
+	hostPublicKey, err := ssh.ParsePublicKey(hostKeyData)
+	if err != nil {
+		slog.Error("Failed to parse SSH host public key", "err", err)
+		fmt.Fprintf(os.Stderr, "\nERROR: Invalid SSH host public key\n")
+		os.Exit(1)
+	}
+
 	// Create SSH config
 	sshConfig := &ssh.ClientConfig{
 		User: *username,
 		Auth: []ssh.AuthMethod{
 			ssh.PublicKeys(signer),
 		},
-		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
+		HostKeyCallback: ssh.FixedHostKey(hostPublicKey),
 		Timeout:         10 * time.Second,
 	}
 
EOF
@@ -20,6 +20,7 @@
sshAddr = flag.String("ssh", "localhost:2222", "SSH address of SONiC VM")
username = flag.String("user", "admin", "SSH username")
sshKey = flag.String("key", "./sshkey", "Path to SSH private key")
hostKey = flag.String("hostkey", "./ssh_hostkey.pub", "Path to SSH host public key")
showStatus = flag.Bool("status", false, "Show agent status instead of uninstalling")
verbose = flag.Bool("v", false, "Verbose logging")
)
@@ -52,13 +53,29 @@
os.Exit(1)
}

// Load SSH host public key
hostKeyData, err := os.ReadFile(*hostKey)
if err != nil {
slog.Error("Failed to read SSH host public key", "path", *hostKey, "err", err)
fmt.Fprintf(os.Stderr, "\nERROR: SSH host public key not found at %s\n", *hostKey)
fmt.Fprintf(os.Stderr, "\nSpecify the path to your SSH host public key with -hostkey\n")
os.Exit(1)
}

hostPublicKey, err := ssh.ParsePublicKey(hostKeyData)
if err != nil {
slog.Error("Failed to parse SSH host public key", "err", err)
fmt.Fprintf(os.Stderr, "\nERROR: Invalid SSH host public key\n")
os.Exit(1)
}

// Create SSH config
sshConfig := &ssh.ClientConfig{
User: *username,
Auth: []ssh.AuthMethod{
ssh.PublicKeys(signer),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
HostKeyCallback: ssh.FixedHostKey(hostPublicKey),
Timeout: 10 * time.Second,
}

Copilot is powered by AI and may make mistakes. Always verify output.
return &ssh.ClientConfig{
User: DefaultUsername,
Auth: authMethods,
HostKeyCallback: ssh.InsecureIgnoreHostKey(),

Check failure

Code scanning / CodeQL

Use of insecure HostKeyCallback implementation High test

Configuring SSH ClientConfig with insecure HostKeyCallback implementation from
this source
.

Copilot Autofix

AI about 1 month ago

To address this issue, replace the insecure ssh.InsecureIgnoreHostKey() callback with a secure alternative that checks the server's public key against a predefined allow list. For this case, since it seems we're connecting to a fixed VM (probably local), using ssh.FixedHostKey(publicKey) is suitable and straightforward. To do this, we need to:

  1. Load the host's public key from a file (commonly "sshkey.pub" next to the private key).
  2. Parse the public key bytes using ssh.ParsePublicKey.
  3. Pass the parsed public key to ssh.FixedHostKey as the value for HostKeyCallback.
  4. Ensure these steps are reflected in the SSHConfig() function (line 288+), and handle errors appropriately (e.g., logging if the host key cannot be loaded).
  5. Add the necessary code to read the host key file in SSHConfig, and any helper function if needed.

Required changes:

  • Read the host's public key (e.g., "./sshkey.pub") in SSHConfig.
  • Create the HostKeyCallback by parsing the public key and using ssh.FixedHostKey.
  • Replace the assignment at line 307.
  • Add any necessary variables, error handling, and potentially an import for reading files (already present via os).

Suggested changeset 1
test/integration/agent-gnmi/pkg/sonicvm/vm.go

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/test/integration/agent-gnmi/pkg/sonicvm/vm.go b/test/integration/agent-gnmi/pkg/sonicvm/vm.go
--- a/test/integration/agent-gnmi/pkg/sonicvm/vm.go
+++ b/test/integration/agent-gnmi/pkg/sonicvm/vm.go
@@ -301,10 +301,35 @@
 		slog.Debug("SSH key not available, will try without it", "path", keyPath, "err", err)
 	}
 
+	// Load the allowed host public key
+	hostKeyPath := keyPath + ".pub"
+	hostKeyData, err := os.ReadFile(hostKeyPath)
+	if err != nil {
+		slog.Warn("SSH host public key could not be loaded", "path", hostKeyPath, "err", err)
+		// For testing, fallback to insecure (remove this for production)
+		return &ssh.ClientConfig{
+			User:            DefaultUsername,
+			Auth:            authMethods,
+			HostKeyCallback: ssh.InsecureIgnoreHostKey(),
+			Timeout:         30 * time.Second,
+		}
+	}
+	hostPublicKey, err := ssh.ParsePublicKey(hostKeyData)
+	if err != nil {
+		slog.Warn("Failed to parse SSH host public key", "path", hostKeyPath, "err", err)
+		// For testing, fallback to insecure (remove this for production)
+		return &ssh.ClientConfig{
+			User:            DefaultUsername,
+			Auth:            authMethods,
+			HostKeyCallback: ssh.InsecureIgnoreHostKey(),
+			Timeout:         30 * time.Second,
+		}
+	}
+
 	return &ssh.ClientConfig{
 		User:            DefaultUsername,
 		Auth:            authMethods,
-		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
+		HostKeyCallback: ssh.FixedHostKey(hostPublicKey),
 		Timeout:         30 * time.Second,
 	}
 }
EOF
@@ -301,10 +301,35 @@
slog.Debug("SSH key not available, will try without it", "path", keyPath, "err", err)
}

// Load the allowed host public key
hostKeyPath := keyPath + ".pub"
hostKeyData, err := os.ReadFile(hostKeyPath)
if err != nil {
slog.Warn("SSH host public key could not be loaded", "path", hostKeyPath, "err", err)
// For testing, fallback to insecure (remove this for production)
return &ssh.ClientConfig{
User: DefaultUsername,
Auth: authMethods,
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
Timeout: 30 * time.Second,
}
}
hostPublicKey, err := ssh.ParsePublicKey(hostKeyData)
if err != nil {
slog.Warn("Failed to parse SSH host public key", "path", hostKeyPath, "err", err)
// For testing, fallback to insecure (remove this for production)
return &ssh.ClientConfig{
User: DefaultUsername,
Auth: authMethods,
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
Timeout: 30 * time.Second,
}
}

return &ssh.ClientConfig{
User: DefaultUsername,
Auth: authMethods,
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
HostKeyCallback: ssh.FixedHostKey(hostPublicKey),
Timeout: 30 * time.Second,
}
}
Copilot is powered by AI and may make mistakes. Always verify output.
@github-actions
Copy link

🚀 Temp artifacts published: v0-38a9d36a9 🚀

@edipascale
Copy link
Contributor

@pau-hedgehog thanks for looking into this! Regardless of the implementation details, having a fast way to spawn a VS that we can connect to via gNMI is exactly what I was looking for. As we discussed offline, I'd skip the agent installation, I'd create an agent as part of the test setup and point it to the VS gNMI server, so that in our unit tests we can directly call the function that configures the switch from an agent config in go and bypass all of the k8s stuff. Let's discuss this with @Frostman when we have time, but I think that with something like this it would be easy to setup some stub tests.

@pau-hedgehog pau-hedgehog changed the title chore(doc): add pipeline information to profiles agent-gnmi test integration proposal/discussion Oct 28, 2025
@pau-hedgehog pau-hedgehog added ci:-vlab Disable VLAB tests ci:-upgrade Disable VLAB upgrade tests labels Oct 28, 2025
@github-actions
Copy link

🚀 Temp artifacts published: v0-38a9d36a9 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:-upgrade Disable VLAB upgrade tests ci:-vlab Disable VLAB tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants