maidn-cli/internal/bootstrap/bootstrap_test.go

152 lines
6 KiB
Go

package bootstrap
import (
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"github.com/Pingu-Studio/MaidnCLI/internal/config"
)
func TestRenderCiliumConfig(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "values.yaml")
if err := os.WriteFile(path, []byte("host: ${CILIUM_K8S_SERVICE_HOST}\ninterface: ${CILIUM_TRAFFIC_INTERFACE}\nstart: ${CILIUM_LB_START}\nend: ${CILIUM_LB_END}\n"), 0644); err != nil {
t.Fatal(err)
}
cfg := config.Config{Talos: config.TalosConfig{KubeconfigEndpoint: "192.168.45.3"}, Cilium: config.CiliumConfig{TrafficInterface: "eth1", LoadBalancerStart: "192.168.45.19", LoadBalancerEnd: "192.168.45.30"}}
if err := renderCiliumConfig(dir, cfg); err != nil {
t.Fatal(err)
}
content, err := os.ReadFile(path)
if err != nil {
t.Fatal(err)
}
if strings.Contains(string(content), "${") || !strings.Contains(string(content), "192.168.45.30") {
t.Fatalf("Cilium configuration was not rendered: %s", content)
}
}
func TestRenderDeliveryConfig(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "webhook.yaml")
if err := os.WriteFile(path, []byte("host: ${WEBHOOK_HOSTNAME}\npath: ${WEBHOOK_PATH}\n"), 0644); err != nil {
t.Fatal(err)
}
cfg := config.Config{Delivery: config.DeliveryConfig{WebhookHostname: "tekton.example.test", WebhookPath: "/hooks/forgejo"}}
if err := renderDeliveryConfig(dir, cfg); err != nil {
t.Fatal(err)
}
content, err := os.ReadFile(path)
if err != nil {
t.Fatal(err)
}
if strings.Contains(string(content), "${") || !strings.Contains(string(content), "/hooks/forgejo") {
t.Fatalf("delivery configuration was not rendered: %s", content)
}
}
func TestRenderDemocraticCSISecret(t *testing.T) {
secret, err := renderDemocraticCSISecret(config.DemocraticCSIConfig{TrueNASAPIKey: "api-key", TrueNASHost: "truenas.example.test", TargetPortal: "truenas.example.test:3260", ShareHost: "truenas.example.test", DatasetParentNFS: "pool/kubernetes/nfs/v", DatasetSnapshotsNFS: "pool/kubernetes/nfs/s", AllowedNetworks: "192.168.45.0/24", NameSuffix: "-test", PortalGroup: "1", InitiatorGroup: "1"})
if err != nil {
t.Fatal(err)
}
if !strings.Contains(string(secret), "name: democratic-csi-secrets") || !strings.Contains(string(secret), "dataset-parent-nfs: pool/kubernetes/nfs/v") {
t.Fatalf("Democratic CSI secret was not rendered: %s", secret)
}
}
func TestWriteDemocraticCSISecretEncryptsValues(t *testing.T) {
if _, err := exec.LookPath("age-keygen"); err != nil {
t.Skip("age-keygen is required for bootstrap encryption")
}
if _, err := exec.LookPath("sops"); err != nil {
t.Skip("sops is required for bootstrap encryption")
}
dir := t.TempDir()
identity := filepath.Join(dir, "age-key.txt")
if err := exec.Command("age-keygen", "-o", identity).Run(); err != nil {
t.Fatal(err)
}
secretPath := filepath.Join(dir, "secret.sops.yaml")
csi := config.DemocraticCSIConfig{TrueNASAPIKey: "test-api-key", TrueNASHost: "truenas.example.test", TargetPortal: "truenas.example.test:3260", ShareHost: "truenas.example.test", DatasetParentNFS: "pool/kubernetes/nfs/v", DatasetSnapshotsNFS: "pool/kubernetes/nfs/s", AllowedNetworks: "192.168.45.0/24", NameSuffix: "-test", PortalGroup: "1", InitiatorGroup: "1"}
if err := writeDemocraticCSISecret(secretPath, csi, identity); err != nil {
t.Fatal(err)
}
encrypted, err := os.ReadFile(secretPath)
if err != nil {
t.Fatal(err)
}
if strings.Contains(string(encrypted), csi.TrueNASAPIKey) || !strings.Contains(string(encrypted), "sops:") {
t.Fatal("Democratic CSI secret was not SOPS encrypted")
}
}
func TestNewWebhookAuthorization(t *testing.T) {
authorization, err := NewWebhookAuthorization()
if err != nil {
t.Fatal(err)
}
if !strings.HasPrefix(authorization, "Bearer ") || len(authorization) <= len("Bearer ") {
t.Fatalf("invalid webhook authorization")
}
}
func TestCopyDirSkipsGitDirectory(t *testing.T) {
source := t.TempDir()
destination := t.TempDir()
if err := os.Mkdir(filepath.Join(source, ".git"), 0755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(source, ".git", "config"), []byte("private"), 0644); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(source, "README.md"), []byte("template"), 0644); err != nil {
t.Fatal(err)
}
if err := copyDir(source, destination, false); err != nil {
t.Fatal(err)
}
if _, err := os.Stat(filepath.Join(destination, ".git")); !os.IsNotExist(err) {
t.Fatal("copied template must not contain its Git metadata")
}
content, err := os.ReadFile(filepath.Join(destination, "README.md"))
if err != nil || string(content) != "template" {
t.Fatalf("template content was not copied: %q, %v", content, err)
}
}
func TestEnsureManifestsKustomizations(t *testing.T) {
dir := t.TempDir()
for _, environment := range []string{"previews", "staging", "production"} {
if err := os.MkdirAll(filepath.Join(dir, "apps", environment), 0755); err != nil {
t.Fatal(err)
}
}
if err := ensureManifestsKustomizations(dir); err != nil {
t.Fatal(err)
}
content, err := os.ReadFile(filepath.Join(dir, "apps", "previews", "kustomization.yaml"))
if err != nil || !strings.Contains(string(content), "resources:") {
t.Fatalf("preview Kustomization was not created: %q, %v", content, err)
}
}
func TestRenderTerraformTFVarsIsStableAndRedactsToken(t *testing.T) {
cfg := config.Config{
ClusterID: "test",
Talos: config.TalosConfig{
Proxmox: config.TalosProxmoxConfig{APIURL: "https://proxmox.test", APITokenID: "id", APITokenSecret: "secret", NodeInterfaces: map[string]string{"b": "eno2", "a": "eno1"}},
Cluster: config.TalosClusterConfig{Name: "test", Domain: "test", DiskStorage: "local", AdditionalStorage: "local"},
Image: config.TalosImageConfig{TalosVersion: "v1.13.6", KubernetesVersion: "v1.33.4", SchematicID: "abcdefghijkl", Architecture: "amd64"},
},
}
first := renderTerraformTFVars(cfg)
second := renderTerraformTFVars(cfg)
if first != second || strings.Contains(first, "secret") || strings.Index(first, `"a"`) > strings.Index(first, `"b"`) {
t.Fatalf("Terraform rendering is not deterministic or redacted: %s", first)
}
}