package installscript_test import ( "bytes" "strings" "testing" "atcr.io/pkg/appview/installscript" ) func mustBrand(t *testing.T, name, display, releases string) installscript.Brand { t.Helper() b, err := installscript.NewBrand(name, display, releases) if err != nil { t.Fatalf("NewBrand(%q, %q, %q) error = %v", name, display, releases, err) } return b } func TestNewBrandDefaultsToATCR(t *testing.T) { b := mustBrand(t, "", "", "") if b.Name != "atcr" { t.Errorf("Name = %q, want atcr", b.Name) } if b.BinaryName() != "docker-credential-atcr" { t.Errorf("BinaryName() = %q", b.BinaryName()) } if b.ConfigDir() != "~/.atcr" { t.Errorf("ConfigDir() = %q", b.ConfigDir()) } if b.DeviceFile() != "~/.atcr/device.json" { t.Errorf("DeviceFile() = %q", b.DeviceFile()) } if b.EnvPrefix() != "ATCR" { t.Errorf("EnvPrefix() = %q", b.EnvPrefix()) } if b.ReleasesBaseURL != installscript.DefaultReleasesBaseURL { t.Errorf("ReleasesBaseURL = %q", b.ReleasesBaseURL) } } func TestNewBrandSeamark(t *testing.T) { b := mustBrand(t, "seamark", "Seamark", "") if b.BinaryName() != "docker-credential-seamark" { t.Errorf("BinaryName() = %q", b.BinaryName()) } if b.DeviceFile() != "~/.seamark/device.json" { t.Errorf("DeviceFile() = %q", b.DeviceFile()) } if b.EnvPrefix() != "SEAMARK" { t.Errorf("EnvPrefix() = %q", b.EnvPrefix()) } } // The name lands inside a shell script and a PowerShell script, so anything // that is not a plain lowercase word has to be refused at config load. func TestNewBrandRejectsUnsafeNames(t *testing.T) { for _, name := range []string{ "ATCR", "sea mark", "sea/mark", "$(id)", "a`id`", "-lead", "sea\nmark", } { if _, err := installscript.NewBrand(name, "", ""); err == nil { t.Errorf("NewBrand(%q) accepted an unsafe name", name) } } } func TestRenderShellSeamark(t *testing.T) { var buf bytes.Buffer err := installscript.RenderShell(&buf, installscript.Params{ Brand: mustBrand(t, "seamark", "Seamark", ""), RegistryHost: "seamark.cr", SiteHost: "seamark.dev", }) if err != nil { t.Fatalf("RenderShell() error = %v", err) } got := buf.String() for _, want := range []string{ "# Seamark Credential Helper Installation Script", "# Usage: curl -fsSL https://seamark.dev/static/install.sh | bash", `BINARY_NAME="docker-credential-seamark"`, `TANGLED_REPO="${SEAMARK_TANGLED_REPO:-` + installscript.DefaultReleasesBaseURL + `}"`, `download/docker-credential-seamark_${version_without_v}_${OS}_${ARCH}.tar.gz`, `{"credHelpers": {"seamark.cr": "seamark"}}`, ` "seamark.cr": "seamark"`, `if [ -n "$SEAMARK_VERSION" ]; then`, `VERSION="$SEAMARK_VERSION"`, "Seamark Credential Helper Installer", } { if !strings.Contains(got, want) { t.Errorf("rendered install.sh missing %q", want) } } // The whole point of the fix: a Seamark deployment must not name atcr // anywhere in the script it hands to `curl | bash`. for _, forbidden := range []string{"atcr", "ATCR"} { if strings.Contains(got, forbidden) { t.Errorf("rendered install.sh still contains %q:\n%s", forbidden, offendingLines(got, forbidden)) } } } func TestRenderPowerShellSeamark(t *testing.T) { var buf bytes.Buffer err := installscript.RenderPowerShell(&buf, installscript.Params{ Brand: mustBrand(t, "seamark", "Seamark", ""), RegistryHost: "seamark.cr", SiteHost: "seamark.dev", }) if err != nil { t.Fatalf("RenderPowerShell() error = %v", err) } got := buf.String() for _, want := range []string{ `$BinaryName = "docker-credential-seamark.exe"`, `$env:SEAMARK_INSTALL_DIR`, `"$env:ProgramFiles\Seamark"`, `docker-credential-seamark_${versionClean}_Windows_${Arch}.tar.gz`, ` "seamark.cr": "seamark"`, } { if !strings.Contains(got, want) { t.Errorf("rendered install.ps1 missing %q", want) } } for _, forbidden := range []string{"atcr", "ATCR"} { if strings.Contains(got, forbidden) { t.Errorf("rendered install.ps1 still contains %q:\n%s", forbidden, offendingLines(got, forbidden)) } } } // The default deployment must keep producing exactly the script it shipped as // a static file, so a rebrand cannot regress atcr.io's documented install. func TestRenderDefaultIsUnchangedATCR(t *testing.T) { p := installscript.Params{ Brand: mustBrand(t, "", "ATCR", ""), RegistryHost: "atcr.io", SiteHost: "atcr.io", } var sh bytes.Buffer if err := installscript.RenderShell(&sh, p); err != nil { t.Fatalf("RenderShell() error = %v", err) } for _, want := range []string{ "# ATCR Credential Helper Installation Script", "# Usage: curl -fsSL https://atcr.io/static/install.sh | bash", `BINARY_NAME="docker-credential-atcr"`, `TANGLED_REPO="${ATCR_TANGLED_REPO:-https://tangled.org/did:plc:e3kzdezk5gsirzh7eoqplc64}"`, `download/docker-credential-atcr_${version_without_v}_${OS}_${ARCH}.tar.gz`, `{"credHelpers": {"atcr.io": "atcr"}}`, ` "atcr.io": "atcr"`, `if [ -n "$ATCR_VERSION" ]; then`, `VERSION="$ATCR_VERSION"`, "ATCR Credential Helper Installer", } { if !strings.Contains(sh.String(), want) { t.Errorf("rendered install.sh missing %q", want) } } if !strings.HasPrefix(sh.String(), "#!/bin/bash\n") { t.Error("rendered install.sh lost its shebang") } var ps bytes.Buffer if err := installscript.RenderPowerShell(&ps, p); err != nil { t.Fatalf("RenderPowerShell() error = %v", err) } for _, want := range []string{ `$BinaryName = "docker-credential-atcr.exe"`, `$env:ATCR_INSTALL_DIR`, `"$env:ProgramFiles\ATCR"`, ` "atcr.io": "atcr"`, } { if !strings.Contains(ps.String(), want) { t.Errorf("rendered install.ps1 missing %q", want) } } } // A registry host that differs from the site host is the Seamark shape: // the UI is seamark.dev, but Docker authenticates against seamark.cr, so the // credHelpers key has to be the registry. func TestCredHelpersKeyIsRegistryNotSite(t *testing.T) { var buf bytes.Buffer err := installscript.RenderShell(&buf, installscript.Params{ Brand: mustBrand(t, "seamark", "Seamark", ""), RegistryHost: "seamark.cr", SiteHost: "seamark.dev", }) if err != nil { t.Fatalf("RenderShell() error = %v", err) } if strings.Contains(buf.String(), `"seamark.dev": "seamark"`) { t.Error("credHelpers key used the site host instead of the registry host") } } func offendingLines(s, needle string) string { var out []string for _, line := range strings.Split(s, "\n") { if strings.Contains(line, needle) { out = append(out, " "+line) } } return strings.Join(out, "\n") }