clusterflags_test.go
Rama main · réplica de lectura del repositorio original.
package main
import (
"io"
"os"
"path/filepath"
"strings"
"testing"
"time"
"github.com/sophotechlabs/spinoza/internal/auth"
)
func fileHolding(t *testing.T, body string) string {
t.Helper()
path := filepath.Join(t.TempDir(), "secret")
err := os.WriteFile(path, []byte(body), 0o600)
if err != nil {
t.Fatalf("writing %s: %v", path, err)
}
return path
}
func servedFlags(t *testing.T, extra ...string) serving {
t.Helper()
args := append([]string{"--cluster-mode", "--public-url", "https://spinoza.example.com"}, extra...)
opts, err := parseFlags(args)
if err != nil {
t.Fatalf("parse: %v", err)
}
return opts.serve
}
func TestWithoutClusterModeNothingAboutServingIsSetUp(t *testing.T) {
opts, err := parseFlags(nil)
if err != nil {
t.Fatalf("parse: %v", err)
}
if opts.serve.on {
t.Fatal("a plain run was set up to serve a cluster")
}
if opts.cluster.Impersonate {
t.Fatal("a plain run would impersonate somebody")
}
if opts.addr != "127.0.0.1:34115" {
t.Fatalf("addr = %q, want the loopback default", opts.addr)
}
}
func TestServingAClusterNeedsToKnowWhereBrowsersReachIt(t *testing.T) {
_, err := parseFlags([]string{"--cluster-mode"})
if err == nil {
t.Fatal("cluster mode started without a public url")
}
if !strings.Contains(err.Error(), "--public-url") {
t.Fatalf("error = %q, want it to name the flag", err.Error())
}
}
func TestAPublicUrlHasToBeOne(t *testing.T) {
cases := map[string]string{
"spinoza.example.com": "http:// or https://",
"https://": "names no host",
"://nope": "public url",
}
for given, want := range cases {
t.Run(given, func(t *testing.T) {
_, err := parseFlags([]string{"--cluster-mode", "--public-url", given})
if err == nil {
t.Fatal("an unusable public url was accepted")
}
if !strings.Contains(err.Error(), want) {
t.Fatalf("error = %q, want it to mention %q", err.Error(), want)
}
})
}
}
func TestAPublicURLMustBeAnOrigin(t *testing.T) {
cases := map[string]string{
"https://spinoza.example.com/spinoza": "path",
"https://spinoza.example.com/%2F": "path",
"https://spinoza.example.com?tenant=x": "query",
"https://spinoza.example.com?": "query",
"https://spinoza.example.com#settings": "fragment",
"https://spinoza.example.com#": "fragment",
"https://user@spinoza.example.com": "credentials",
}
for given, want := range cases {
t.Run(given, func(t *testing.T) {
_, err := parseFlags([]string{"--cluster-mode", "--public-url", given})
if err == nil {
t.Fatal("a public url that is not an origin was accepted")
}
if !strings.Contains(err.Error(), want) {
t.Fatalf("error = %q, want it to mention %q", err.Error(), want)
}
})
}
}
func TestHTTPOriginsAreAcceptedAsPublicURLs(t *testing.T) {
for _, given := range []string{
"https://spinoza.example.com",
"https://spinoza.example.com/",
"http://127.0.0.1:8080",
"https://[2001:db8::1]:8443/",
} {
t.Run(given, func(t *testing.T) {
_, err := parseFlags([]string{"--cluster-mode", "--public-url", given})
if err != nil {
t.Fatalf("origin was refused: %v", err)
}
})
}
}
func TestRemotePublicHTTPRequiresAnExplicitUnsafeOptIn(t *testing.T) {
_, err := parseFlags([]string{"--cluster-mode", "--public-url", "http://spinoza.example.com"})
if err == nil || !strings.Contains(err.Error(), "--unsafe-allow-http") {
t.Fatalf("plaintext public url error = %v", err)
}
_, err = parseFlags([]string{
"--cluster-mode",
"--public-url", "http://spinoza.example.com",
"--unsafe-allow-http",
})
if err != nil {
t.Fatalf("explicit plaintext public url: %v", err)
}
}
func TestServingMovesTheListenAddressOffLoopback(t *testing.T) {
if got := servedListen(t); got != clusterAddr {
t.Fatalf("addr = %q, want %q so the service can reach the pod", got, clusterAddr)
}
}
func servedListen(t *testing.T, extra ...string) string {
t.Helper()
args := append([]string{"--cluster-mode", "--public-url", "https://spinoza.example.com"}, extra...)
opts, err := parseFlags(args)
if err != nil {
t.Fatalf("parse: %v", err)
}
return opts.addr
}
func TestAnAddressYouNamedYourselfIsKept(t *testing.T) {
if got := servedListen(t, "--addr", "127.0.0.1:9000"); got != "127.0.0.1:9000" {
t.Fatalf("addr = %q, want the one that was asked for", got)
}
}
func TestAnAddressFromTheEnvironmentIsKept(t *testing.T) {
t.Setenv("SPINOZA_ADDR", "0.0.0.0:9999")
if got := servedListen(t); got != "0.0.0.0:9999" {
t.Fatalf("addr = %q, want the one in the environment", got)
}
}
func TestTheCallbackAndTheLandingPageComeFromThePublicUrl(t *testing.T) {
for _, extra := range [][]string{
nil,
{"--public-url", "https://spinoza.example.com/"},
} {
got := servedFlags(t, extra...)
if got.auth.OIDC.RedirectURL != "https://spinoza.example.com/auth/callback" {
t.Fatalf("redirect = %q", got.auth.OIDC.RedirectURL)
}
if got.auth.OIDC.PostLogoutURL != "https://spinoza.example.com/" {
t.Fatalf("post logout = %q", got.auth.OIDC.PostLogoutURL)
}
}
}
func TestARedirectYouRegisteredYourselfIsKept(t *testing.T) {
got := servedFlags(
t,
"--auth-oidc-redirect-url", "https://tools.example.com/spinoza/auth/callback",
"--auth-oidc-post-logout-url", "https://tools.example.com/spinoza/",
)
if got.auth.OIDC.RedirectURL != "https://tools.example.com/spinoza/auth/callback" {
t.Fatalf("redirect = %q", got.auth.OIDC.RedirectURL)
}
if got.auth.OIDC.PostLogoutURL != "https://tools.example.com/spinoza/" {
t.Fatalf("post logout = %q", got.auth.OIDC.PostLogoutURL)
}
}
func TestServingActsAsWhoeverIsSignedInUnlessYouSayOtherwise(t *testing.T) {
opts, err := parseFlags([]string{"--cluster-mode", "--public-url", "https://spinoza.example.com"})
if err != nil {
t.Fatalf("parse: %v", err)
}
if !opts.cluster.Impersonate {
t.Fatal("cluster mode would act as spinoza's own service account by default")
}
off, offErr := parseFlags([]string{
"--cluster-mode", "--public-url", "https://spinoza.example.com", "--impersonate=false",
})
if offErr != nil {
t.Fatalf("parse: %v", offErr)
}
if off.cluster.Impersonate {
t.Fatal("impersonation stayed on after it was turned off")
}
}
func TestEveryAuthFlagReachesTheConfig(t *testing.T) {
got := servedFlags(
t,
"--auth-mode", "oidc",
"--allow-anonymous-admin",
"--session-ttl", "30m",
"--auth-default-role", "editor",
"--auth-admin-groups", "platform-admins",
"--auth-editor-groups", "platform, sre",
"--auth-viewer-groups", "everyone",
"--auth-user-header", "X-User",
"--auth-groups-header", "X-Groups",
"--auth-proxy-secret-header", "X-Proxy-Token",
"--auth-proxy-secret-file", fileHolding(t, "proxy-secret\n"),
"--auth-proxy-logout-url", "https://proxy/sign_out",
"--auth-proxy-websocket-max-age", "7m",
"--auth-oidc-issuer", "https://keycloak.example.com/realms/main",
"--auth-oidc-internal-issuer", "http://keycloak.keycloak.svc/realms/main",
"--auth-oidc-client-id", "spinoza",
"--auth-oidc-client-secret", "shh",
"--auth-oidc-scopes", "openid,profile",
"--auth-oidc-groups-claim", "roles",
"--auth-oidc-username-claims", "email,sub",
"--auth-oidc-username-prefix", "oidc:",
"--auth-oidc-groups-prefix", "oidc:",
"--auth-oidc-ca-cert", "/etc/spinoza/ca.crt",
"--auth-oidc-unsafe-allow-http",
"--auth-oidc-backchannel-logout",
)
if got.auth.Mode != auth.ModeOIDC {
t.Fatalf("mode = %q", got.auth.Mode)
}
if !got.auth.AllowAnonymous {
t.Fatal("the anonymous admin opt-in did not reach auth config")
}
if got.auth.SessionTTL != 30*time.Minute {
t.Fatalf("ttl = %s", got.auth.SessionTTL)
}
if got.auth.DefaultRole != auth.RoleEditor {
t.Fatalf("default role = %q", got.auth.DefaultRole)
}
if strings.Join(got.auth.EditorGroups, ",") != "platform,sre" {
t.Fatalf("editor groups = %v", got.auth.EditorGroups)
}
if got.auth.AdminGroups[0] != "platform-admins" || got.auth.ViewerGroups[0] != "everyone" {
t.Fatalf("groups = %+v", got.auth)
}
if got.auth.Proxy.UserHeader != "X-User" || got.auth.Proxy.GroupsHeader != "X-Groups" {
t.Fatalf("proxy = %+v", got.auth.Proxy)
}
if got.auth.Proxy.SecretHeader != "X-Proxy-Token" || string(got.auth.Proxy.SharedSecret) != "proxy-secret" {
t.Fatalf("proxy authentication = %+v", got.auth.Proxy)
}
if got.auth.Proxy.LogoutURL != "https://proxy/sign_out" {
t.Fatalf("proxy logout = %q", got.auth.Proxy.LogoutURL)
}
if got.auth.Proxy.WebSocketMaxAge != 7*time.Minute {
t.Fatalf("proxy websocket max age = %s", got.auth.Proxy.WebSocketMaxAge)
}
oidc := got.auth.OIDC
if oidc.IssuerURL != "https://keycloak.example.com/realms/main" {
t.Fatalf("issuer = %q", oidc.IssuerURL)
}
if oidc.InternalIssuerURL != "http://keycloak.keycloak.svc/realms/main" {
t.Fatalf("internal issuer = %q", oidc.InternalIssuerURL)
}
if oidc.ClientID != "spinoza" || oidc.ClientSecret != "shh" {
t.Fatalf("client = %q/%q", oidc.ClientID, oidc.ClientSecret)
}
if strings.Join(oidc.Scopes, " ") != "openid profile" {
t.Fatalf("scopes = %v", oidc.Scopes)
}
if oidc.GroupsClaim != "roles" || strings.Join(oidc.UsernameClaims, ",") != "email,sub" {
t.Fatalf("claims = %q/%v", oidc.GroupsClaim, oidc.UsernameClaims)
}
if oidc.UsernamePrefix != "oidc:" || oidc.GroupsPrefix != "oidc:" {
t.Fatalf("prefixes = %q/%q", oidc.UsernamePrefix, oidc.GroupsPrefix)
}
if oidc.CACertFile != "/etc/spinoza/ca.crt" || !oidc.BackchannelLogout {
t.Fatalf("oidc = %+v", oidc)
}
if !oidc.UnsafeAllowHTTP {
t.Fatal("the oidc plaintext opt-in was dropped")
}
}
func TestSecretsComeFromFilesWithoutTheirTrailingNewline(t *testing.T) {
got := servedFlags(
t,
"--session-secret-file", fileHolding(t, "signing-key\n"),
"--auth-oidc-client-secret-file", fileHolding(t, "client-secret\n"),
"--auth-oidc-client-secret", "ignored",
)
if string(got.auth.SessionSecret) != "signing-key" {
t.Fatalf("session secret = %q", string(got.auth.SessionSecret))
}
if got.auth.OIDC.ClientSecret != "client-secret" {
t.Fatalf("client secret = %q, want the file to win over the flag", got.auth.OIDC.ClientSecret)
}
}
func TestASecretFileThatIsNotThereStopsSpinozaStarting(t *testing.T) {
for _, flag := range []string{"--session-secret-file", "--auth-proxy-secret-file", "--auth-oidc-client-secret-file"} {
t.Run(flag, func(t *testing.T) {
_, err := parseFlags([]string{
"--cluster-mode", "--public-url", "https://spinoza.example.com", flag, "/no/such/file",
})
if err == nil {
t.Fatal("a missing secret file was accepted")
}
if !strings.Contains(err.Error(), "/no/such/file") {
t.Fatalf("error = %q, want it to name the file", err.Error())
}
})
}
}
func TestAnOversizedSecretFileStopsSpinozaStarting(t *testing.T) {
path := fileHolding(t, "secret")
if err := os.Truncate(path, maxSecretBytes+1); err != nil {
t.Fatalf("enlarge secret: %v", err)
}
_, err := readSecret(path, "")
if err == nil || !strings.Contains(err.Error(), "larger than") {
t.Fatalf("reading oversized secret = %v, want the size limit", err)
}
}
func TestTheSessionSecretCanComeFromTheEnvironment(t *testing.T) {
t.Setenv(secretEnv, "from-the-environment")
if string(servedFlags(t).auth.SessionSecret) != "from-the-environment" {
t.Fatal("the session secret in the environment was not read")
}
}
func TestAnEmptyEnvironmentValueLeavesTheDefaultAlone(t *testing.T) {
t.Setenv("SPINOZA_IMPERSONATE", "")
if !envUnless("SPINOZA_IMPERSONATE") {
t.Fatal("an empty environment variable turned a default off")
}
t.Setenv("SPINOZA_IMPERSONATE", "false")
if envUnless("SPINOZA_IMPERSONATE") {
t.Fatal("the environment did not turn the default off")
}
if !envUnless("SPINOZA_NOT_SET_ANYWHERE") {
t.Fatal("a variable nobody set changed the default")
}
}
func TestTheVersionAndTheLicenceStillPrintInsideTheImage(t *testing.T) {
t.Setenv("SPINOZA_CLUSTER_MODE", "true")
for _, flag := range []string{"--version", "--license"} {
t.Run(flag, func(t *testing.T) {
opts, err := parseFlags([]string{flag})
if err != nil {
t.Fatalf("%s asked for the public url before printing: %v", flag, err)
}
if !printedNotice(io.Discard, opts) {
t.Fatalf("%s printed nothing", flag)
}
})
}
}