Files
2026-04-17 15:30:22 +01:00

143 lines
3.9 KiB
Go

package knownhosts
import (
"testing"
"github.com/andydixon/nexus/internal/models"
)
// ---------------------------------------------------------------------------
// Mock storage implementation
// ---------------------------------------------------------------------------
type mockStorage struct {
hosts map[string]*models.KnownHost // keyed by "host:port"
}
func newMockStorage() *mockStorage {
return &mockStorage{hosts: make(map[string]*models.KnownHost)}
}
func (m *mockStorage) key(host string, port int) string {
return host + ":" + string(rune(port))
}
func (m *mockStorage) GetKnownHost(host string, port int) (*models.KnownHost, error) {
kh, ok := m.hosts[m.key(host, port)]
if !ok {
return nil, nil
}
return kh, nil
}
func (m *mockStorage) SaveKnownHost(kh *models.KnownHost) error {
m.hosts[m.key(kh.Host, kh.Port)] = kh
return nil
}
func (m *mockStorage) ListKnownHosts() ([]*models.KnownHost, error) {
result := make([]*models.KnownHost, 0, len(m.hosts))
for _, kh := range m.hosts {
result = append(result, kh)
}
return result, nil
}
func (m *mockStorage) DeleteKnownHost(id string) error {
for k, kh := range m.hosts {
if kh.ID == id {
delete(m.hosts, k)
return nil
}
}
return nil
}
// ---------------------------------------------------------------------------
// Verify unknown host returns false (no error)
// ---------------------------------------------------------------------------
func TestVerifyUnknownHost(t *testing.T) {
store := NewStore(newMockStorage())
trusted, err := store.Verify("unknown.example.com", 22, "ssh-ed25519", "SHA256:abc", "pubkey")
if err != nil {
t.Fatalf("Verify() unexpected error = %v", err)
}
if trusted {
t.Error("expected trusted = false for unknown host")
}
}
// ---------------------------------------------------------------------------
// Accept then verify returns true
// ---------------------------------------------------------------------------
func TestAcceptThenVerify(t *testing.T) {
store := NewStore(newMockStorage())
if err := store.Accept("server.example.com", 22, "ssh-ed25519", "SHA256:abc", "pubkey"); err != nil {
t.Fatalf("Accept() error = %v", err)
}
trusted, err := store.Verify("server.example.com", 22, "ssh-ed25519", "SHA256:abc", "pubkey")
if err != nil {
t.Fatalf("Verify() error = %v", err)
}
if !trusted {
t.Error("expected trusted = true after Accept()")
}
}
// ---------------------------------------------------------------------------
// Changed fingerprint returns error
// ---------------------------------------------------------------------------
func TestVerifyChangedFingerprint(t *testing.T) {
store := NewStore(newMockStorage())
// Accept with fingerprint A.
if err := store.Accept("host.local", 22, "ssh-rsa", "SHA256:original", "pubkeyA"); err != nil {
t.Fatalf("Accept() error = %v", err)
}
// Verify with fingerprint B — should return an error indicating a change.
trusted, err := store.Verify("host.local", 22, "ssh-rsa", "SHA256:changed", "pubkeyB")
if err == nil {
t.Fatal("expected error for changed fingerprint")
}
if trusted {
t.Error("expected trusted = false for changed fingerprint")
}
}
// ---------------------------------------------------------------------------
// List and Delete operations
// ---------------------------------------------------------------------------
func TestListAndDelete(t *testing.T) {
mock := newMockStorage()
store := NewStore(mock)
_ = store.Accept("host-a.local", 22, "ssh-ed25519", "fp-a", "pk-a")
_ = store.Accept("host-b.local", 22, "ssh-rsa", "fp-b", "pk-b")
entries, err := store.List()
if err != nil {
t.Fatalf("List() error = %v", err)
}
if len(entries) != 2 {
t.Fatalf("expected 2 entries, got %d", len(entries))
}
// Delete the first entry.
if err := store.Delete(entries[0].ID); err != nil {
t.Fatalf("Delete() error = %v", err)
}
entries, _ = store.List()
if len(entries) != 1 {
t.Errorf("expected 1 entry after delete, got %d", len(entries))
}
}