metis/pkg/plan/node_identity_boot_test.go
codex 62131596fc
All checks were successful
Tests / Declarative: Post Actions passed: 314
test: verify recovered image markers cannot skip credentials
2026-10-04 00:29:37 -05:00

108 lines
3.3 KiB
Go

package plan
import (
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"metis/pkg/config"
)
// Exercise the generated script with synthetic credentials and fake host tools.
func TestIdentityFailureAndRetry(t *testing.T) {
root := t.TempDir()
etc := filepath.Join(root, "etc/metis")
state := filepath.Join(root, "var/lib/metis")
bin := filepath.Join(root, "bin")
for _, dir := range []string{etc, state, bin, filepath.Join(root, "etc/sudoers.d")} {
if err := os.MkdirAll(dir, 0700); err != nil {
t.Fatal(err)
}
}
envPath := filepath.Join(etc, "firstboot.env")
synthetic := "METIS_HOSTNAME='test'\nMETIS_ATLAS_PASSWORD='synthetic-atlas'\nMETIS_ROOT_PASSWORD='synthetic-root'\n"
if err := os.WriteFile(envPath, []byte(synthetic), 0600); err != nil {
t.Fatal(err)
}
commands := map[string]string{
"id": "exit 0", "getent": "exit 1", "visudo": "exit 0",
"chpasswd": "cat >/dev/null\n[ \"${FAIL_PASSWORD:-0}\" = 0 ]",
}
for name, body := range commands {
if err := os.WriteFile(filepath.Join(bin, name), []byte("#!/bin/sh\n"+body+"\n"), 0700); err != nil {
t.Fatal(err)
}
}
script := strings.NewReplacer("/etc/metis", etc, "/var/lib/metis", state, "/etc/sudoers.d", filepath.Join(root, "etc/sudoers.d")).Replace(nodeIdentityScriptContent())
path := filepath.Join(root, "identity.sh")
if err := os.WriteFile(path, []byte(script), 0700); err != nil {
t.Fatal(err)
}
run := func(fail string) error {
cmd := exec.Command("bash", path)
cmd.Env = append(os.Environ(), "PATH="+bin+":"+os.Getenv("PATH"), "FAIL_PASSWORD="+fail)
out, err := cmd.CombinedOutput()
if strings.Contains(string(out), "synthetic-") {
t.Fatal("password in output")
}
return err
}
if run("1") == nil {
t.Fatal("password failure must propagate")
}
marker := filepath.Join(state, "node-identity-applied.done")
if _, err := os.Stat(marker); !os.IsNotExist(err) {
t.Fatal("failed setup marked complete")
}
if err := run("0"); err != nil {
t.Fatal(err)
}
if _, err := os.Stat(marker); err != nil {
t.Fatal(err)
}
clean, err := os.ReadFile(envPath)
if err != nil {
t.Fatal(err)
}
if strings.Contains(string(clean), "PASSWORD") || strings.Contains(string(clean), "synthetic-") {
t.Fatal("password persisted after application")
}
if err := run("1"); err != nil {
t.Fatal("completed setup should not reset passwords", err)
}
// Re-injection into a previously booted image must not trust its old marker.
if err := os.WriteFile(filepath.Join(etc, "node-identity.pending"), []byte("pending"), 0600); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(envPath, []byte(synthetic), 0600); err != nil {
t.Fatal(err)
}
if run("1") == nil {
t.Fatal("old marker suppressed newly injected credentials")
}
if err := run("0"); err != nil {
t.Fatal(err)
}
if _, err := os.Stat(filepath.Join(etc, "node-identity.pending")); !os.IsNotExist(err) {
t.Fatal("successful identity left a pending marker")
}
}
func TestIdentityEnabledWithoutCloudInit(t *testing.T) {
files, err := buildFiles(&config.NodeConfig{Hostname: "test", SSHUser: "atlas"}, nil)
if err != nil {
t.Fatal(err)
}
enabled := false
for _, f := range files {
if f.Path == "etc/systemd/system/multi-user.target.wants/metis-node-identity.service" {
enabled = f.Symlink == "../metis-node-identity.service"
}
}
if !enabled {
t.Fatal("identity service is not enabled in image")
}
}