package bootstrap import ( "errors" "os" "path/filepath" "strings" "testing" "github.com/Pingu-Studio/MaidnCLI/internal/config" ) func TestEnsureTemplateRevisionsLocksFirstCheckout(t *testing.T) { workspace, cfg, git := templateRevisionTestConfig(t) useTemplateRevisionGit(t, git) if err := ensureTemplateRevisions(workspace, cfg); err != nil { t.Fatal(err) } lock, err := readTemplateRevisionLock(filepath.Join(workspace, "maidn-template-revisions.yaml")) if err != nil { t.Fatal(err) } if lock.CICD.Commit != git.commits["cicd"] || lock.Manifests.Commit != git.commits["manifests"] || lock.Talos.Commit != git.commits["talos"] { t.Fatalf("lock did not record checked-out commits: %#v", lock) } data, err := os.ReadFile(filepath.Join(workspace, "maidn-template-revisions.yaml")) if err != nil { t.Fatal(err) } if strings.Contains(string(data), "template-password") || strings.Contains(git.commands(), "template-password") { t.Fatal("template credentials reached the lock or Git command arguments") } } func TestEnsureTemplateRevisionsReusesLockedCommitAfterBranchDrift(t *testing.T) { workspace, cfg, git := templateRevisionTestConfig(t) useTemplateRevisionGit(t, git) if err := ensureTemplateRevisions(workspace, cfg); err != nil { t.Fatal(err) } locked := git.commits["cicd"] git.commits["cicd"] = strings.Repeat("d", 40) git.resetCalls() if err := ensureTemplateRevisions(workspace, cfg); err != nil { t.Fatal(err) } if git.fetched["cicd"] != locked || git.checkedOut["cicd"] != locked { t.Fatalf("branch drift changed locked CICD revision: fetched %q, checked out %q", git.fetched["cicd"], git.checkedOut["cicd"]) } if strings.Contains(git.commands(), "fetch origin main") { t.Fatal("later run fetched a mutable branch instead of the lock commit") } } func TestEnsureTemplateRevisionsRejectsChangedRefWithoutGit(t *testing.T) { workspace, cfg, git := templateRevisionTestConfig(t) useTemplateRevisionGit(t, git) if err := ensureTemplateRevisions(workspace, cfg); err != nil { t.Fatal(err) } git.resetCalls() cfg.Templates.CICDRepoRef = "release" err := ensureTemplateRevisions(workspace, cfg) if err == nil || !strings.Contains(err.Error(), "workspace revision lock") || !strings.Contains(err.Error(), "new empty workspaceDir") { t.Fatalf("changed ref error was not safe and actionable: %v", err) } if git.commands() != "" { t.Fatal("changed ref touched Git before rejecting the lock mismatch") } } func TestEnsureTemplateRevisionsHidesSourceWhenLockedCommitIsUnavailable(t *testing.T) { workspace, cfg, git := templateRevisionTestConfig(t) useTemplateRevisionGit(t, git) if err := ensureTemplateRevisions(workspace, cfg); err != nil { t.Fatal(err) } git.failFetch = true err := ensureTemplateRevisions(workspace, cfg) if err == nil || !strings.Contains(err.Error(), "locked template revision cannot be resolved") || !strings.Contains(err.Error(), "new empty workspaceDir") || strings.Contains(err.Error(), "template-password") { t.Fatalf("locked revision failure exposed source details or lacked recovery guidance: %v", err) } } func TestEnsureTemplateRevisionsAllowsOnlyGeneratedTalosChanges(t *testing.T) { workspace, cfg, git := templateRevisionTestConfig(t) useTemplateRevisionGit(t, git) if err := ensureTemplateRevisions(workspace, cfg); err != nil { t.Fatal(err) } git.dirty["talos"] = []string{" M generated/talsecret.yaml", "?? generated/clusterconfig/talosconfig"} if err := ensureTemplateRevisions(workspace, cfg); err != nil { t.Fatalf("generated Talos changes blocked reconciliation: %v", err) } git.dirty["talos"] = []string{" M terraform/main.tf"} if err := ensureTemplateRevisions(workspace, cfg); err == nil { t.Fatal("Talos changes outside generated directory were accepted") } if !hasUnexpectedTemplateChanges([]byte(" M generated/../terraform/main.tf\x00"), "generated") { t.Fatal("Talos changes escaping the generated directory were accepted") } } func TestTemplateGitRunnerUsesTemporaryAskPassForPrivateSource(t *testing.T) { original := runGitEnvironment t.Cleanup(func() { runGitEnvironment = original }) var environment []string var command string runGitEnvironment = func(_ string, env []string, args ...string) ([]byte, error) { environment = env command = strings.Join(args, " ") return nil, nil } source := "https://reader:template-password@git.example.test/templates/cicd.git" repository := config.RedactURL(source) run, cleanup, err := templateGitRunner(config.Config{}, source, repository) if err != nil { t.Fatal(err) } defer cleanup() if _, err := run("", "clone", repository, "checkout"); err != nil { t.Fatal(err) } var askPass string for _, item := range environment { if strings.HasPrefix(item, "GIT_ASKPASS=") { askPass = strings.TrimPrefix(item, "GIT_ASKPASS=") } } if askPass == "" || strings.Contains(command, "template-password") || strings.Contains(command, "reader:") { t.Fatalf("private template checkout did not isolate credentials: command=%q", command) } if _, err := os.Stat(askPass); err != nil { t.Fatalf("temporary askpass script was not created: %v", err) } } func TestEnsureTemplateRevisionsRejectsCredentialBearingExistingOrigin(t *testing.T) { workspace, cfg, git := templateRevisionTestConfig(t) useTemplateRevisionGit(t, git) if err := ensureTemplateRevisions(workspace, cfg); err != nil { t.Fatal(err) } git.origins[filepath.Join(workspace, "maidn-cicd-cluster-template")] = cfg.Templates.CICDRepoURL if err := ensureTemplateRevisions(workspace, cfg); err == nil || strings.Contains(err.Error(), "template-password") { t.Fatalf("credential-bearing checkout origin was accepted or exposed: %v", err) } } func templateRevisionTestConfig(t *testing.T) (string, config.Config, *fakeTemplateGit) { t.Helper() workspace := t.TempDir() cloneParent := filepath.Join(workspace, "checkouts") if err := os.MkdirAll(cloneParent, 0755); err != nil { t.Fatal(err) } git := &fakeTemplateGit{ commits: map[string]string{ "cicd": strings.Repeat("a", 40), "manifests": strings.Repeat("b", 40), "talos": strings.Repeat("c", 40), }, origins: map[string]string{}, fetched: map[string]string{}, checkedOut: map[string]string{}, dirty: map[string][]string{}, } return workspace, config.Config{ WorkspaceDir: workspace, Git: config.GitConfig{CloneParent: cloneParent}, Talos: config.TalosConfig{RepoDirName: "talos", GeneratedDir: "generated"}, Templates: config.TemplateConfig{ CICDRepoURL: "https://reader:template-password@git.example.test/templates/cicd.git", CICDRepoRef: "main", ManifestsRepoURL: "https://git.example.test/templates/manifests.git", ManifestsRepoRef: "main", TalosRepoURL: "https://git.example.test/templates/talos.git", TalosRepoRef: "main", }, }, git } func useTemplateRevisionGit(t *testing.T, git *fakeTemplateGit) { t.Helper() original := runGit runGit = git.run originalEnvironment := runGitEnvironment runGitEnvironment = func(dir string, _ []string, args ...string) ([]byte, error) { return git.run(dir, args...) } t.Cleanup(func() { runGit = original runGitEnvironment = originalEnvironment }) } type fakeTemplateGit struct { commits map[string]string origins map[string]string fetched map[string]string checkedOut map[string]string dirty map[string][]string calls []string failFetch bool } func (git *fakeTemplateGit) run(dir string, args ...string) ([]byte, error) { git.calls = append(git.calls, strings.Join(args, " ")) if len(args) == 0 { return nil, errors.New("missing Git command") } switch args[0] { case "clone": dir = args[len(args)-1] if err := os.MkdirAll(dir, 0755); err != nil { return nil, err } git.origins[dir] = args[len(args)-2] return nil, nil case "remote": return []byte(git.origins[dir] + "\n"), nil case "status": if records := git.dirty[git.templateName(dir)]; len(records) != 0 { return []byte(strings.Join(records, "\x00") + "\x00"), nil } return nil, nil case "fetch": if git.failFetch { return nil, errors.New("not found") } target := args[len(args)-1] name := git.templateName(dir) if len(target) == 40 { git.fetched[name] = target } else { git.fetched[name] = git.commits[name] } return nil, nil case "checkout": git.checkedOut[git.templateName(dir)] = args[len(args)-1] return nil, nil case "rev-parse": if len(args) == 2 && args[1] == "--is-inside-work-tree" { return []byte("true\n"), nil } target := args[len(args)-1] if target == "FETCH_HEAD^{commit}" { return []byte(git.fetched[git.templateName(dir)] + "\n"), nil } if target == "HEAD^{commit}" { return []byte(git.checkedOut[git.templateName(dir)] + "\n"), nil } } return nil, errors.New("unexpected Git command") } func (git *fakeTemplateGit) templateName(dir string) string { switch filepath.Base(dir) { case "maidn-cicd-cluster-template": return "cicd" case "cicd-deployment-manifests-template": return "manifests" default: return "talos" } } func (git *fakeTemplateGit) resetCalls() { git.calls = nil } func (git *fakeTemplateGit) commands() string { return strings.Join(git.calls, "\n") }