package host import ( "bytes" "context" "errors" "os" "path/filepath" "strings" "testing" "time" "github.com/carlosframework/platform/internal/activator" ) func TestScheduleTokenFencePreservesEnvironment(t *testing.T) { for _, content := range []string{"", "APP_SETTING=retained\n", "APP_SETTING=retained\nCARLOS_ADMIN_TOKEN=" + strings.Repeat("a", 64) + "\n"} { name := "missing-file" if content != "" { name = "existing-without-token" } if strings.Contains(content, "CARLOS_ADMIN_TOKEN") { name = "existing-token" } t.Run(name, func(t *testing.T) { dd := t.TempDir() const host = "fenced.example.com" path := filepath.Join(dd, host+".env") if content != "" { if err := os.WriteFile(path, []byte(content), 0o644); err != nil { t.Fatal(err) } if err := os.Chmod(path, 0o644); err != nil { t.Fatal(err) } } svc := &activator.Service{} ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() if _, err := svc.FenceAndStop(ctx, host, 1); !errors.Is(err, activator.ErrStopUnproven) { t.Fatal(err) } // Exercise the actual runner wiring, including the nil-store arm. sd := newScheduleDeps(nil, nil, svc, nil, dd) if token, err := sd.runner.Token(host); token != "" || !errors.Is(err, activator.ErrFenced) { t.Fatalf("fenced token: present=%v err=%v", token != "", err) } raw, err := os.ReadFile(path) if content == "" { if !os.IsNotExist(err) { t.Fatalf("fence created env: %v", err) } return } if err != nil || !bytes.Equal(raw, []byte(content)) { t.Fatalf("fence changed bytes: %v", err) } fi, err := os.Stat(path) if err != nil { t.Fatal(err) } if fi.Mode().Perm() != 0o644 { t.Fatalf("fence changed mode: %o", fi.Mode().Perm()) } }) } } func TestScheduleTokenUnfencedManagedPreparation(t *testing.T) { dd := t.TempDir() const host = "ordinary.example.com" path := filepath.Join(dd, host+".env") if err := os.WriteFile(path, []byte("APP_SETTING=retained\n"), 0o644); err != nil { t.Fatal(err) } sd := newScheduleDeps(nil, nil, &activator.Service{}, nil, dd) first, err := sd.runner.Token(host) if err != nil || len(first) != 64 { t.Fatalf("mint: present=%v err=%v", first != "", err) } if err := os.Chmod(path, 0o644); err != nil { t.Fatal(err) } second, err := sd.runner.Token(host) if err != nil || first != second { t.Fatalf("retained token: %v", err) } raw, err := os.ReadFile(path) if err != nil { t.Fatal(err) } if !bytes.HasPrefix(raw, []byte("APP_SETTING=retained\n")) || bytes.Count(raw, []byte("CARLOS_ADMIN_TOKEN=")) != 1 { t.Fatal("ordinary token preparation lost environment or duplicated token") } fi, err := os.Stat(path) if err != nil { t.Fatal(err) } if fi.Mode().Perm() != 0o600 { t.Fatalf("ordinary mode: %o", fi.Mode().Perm()) } }