feat(config): add GENIUSRUN_FRONTEND_URL, defaulting to PublicBaseURL
Lets the OIDC callback redirect to the frontend's real origin instead of a relative path resolved against the backend's own origin -- needed for this project's own supported split-origin local dev setup (frontend on Vite, backend on geniusrund, bridged by CORS). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -44,6 +44,17 @@ type Config struct {
|
|||||||
// instead of requiring both to be configured separately and risking them
|
// instead of requiring both to be configured separately and risking them
|
||||||
// drifting out of sync.
|
// drifting out of sync.
|
||||||
PublicBaseURL string
|
PublicBaseURL string
|
||||||
|
// FrontendURL is the origin the browser should land on after the OIDC
|
||||||
|
// callback (both success and failure) -- e.g. "http://localhost:5173" in
|
||||||
|
// local dev, where the frontend and backend are different origins
|
||||||
|
// bridged by CORS (see internal/api's corsMiddleware and
|
||||||
|
// frontend/src/api/client.ts's BASE_URL). Defaults to PublicBaseURL when
|
||||||
|
// unset, which is correct for the common production topology where a
|
||||||
|
// reverse proxy unifies frontend and backend under one origin.
|
||||||
|
// PublicBaseURL itself must stay pointed at the backend's own origin
|
||||||
|
// regardless -- it derives OIDCRedirectURL and post_logout_redirect_uri,
|
||||||
|
// which must match wherever those routes are actually served.
|
||||||
|
FrontendURL string
|
||||||
OIDCIssuerURL string
|
OIDCIssuerURL string
|
||||||
OIDCClientID string
|
OIDCClientID string
|
||||||
OIDCClientSecret string
|
OIDCClientSecret string
|
||||||
@@ -80,6 +91,7 @@ func Load() (Config, error) {
|
|||||||
if cfg.PublicBaseURL == "" {
|
if cfg.PublicBaseURL == "" {
|
||||||
return cfg, fmt.Errorf("GENIUSRUN_PUBLIC_BASE_URL is required (e.g. https://geniusrun.example.com)")
|
return cfg, fmt.Errorf("GENIUSRUN_PUBLIC_BASE_URL is required (e.g. https://geniusrun.example.com)")
|
||||||
}
|
}
|
||||||
|
cfg.FrontendURL = strings.TrimRight(getEnvDefault("GENIUSRUN_FRONTEND_URL", cfg.PublicBaseURL), "/")
|
||||||
if cfg.OIDCIssuerURL == "" {
|
if cfg.OIDCIssuerURL == "" {
|
||||||
return cfg, fmt.Errorf("GENIUSRUN_OIDC_ISSUER_URL is required")
|
return cfg, fmt.Errorf("GENIUSRUN_OIDC_ISSUER_URL is required")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,6 +134,32 @@ func TestLoad_GarminPythonPathExplicitOverridesDefault(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLoad_FrontendURLDefaultsToPublicBaseURL(t *testing.T) {
|
||||||
|
setRequiredEnv(t)
|
||||||
|
t.Setenv("GENIUSRUN_FRONTEND_URL", "")
|
||||||
|
|
||||||
|
cfg, err := Load()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Load: %v", err)
|
||||||
|
}
|
||||||
|
if cfg.FrontendURL != cfg.PublicBaseURL {
|
||||||
|
t.Errorf("FrontendURL = %q, want it to default to PublicBaseURL %q", cfg.FrontendURL, cfg.PublicBaseURL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoad_FrontendURLExplicitOverridesDefault(t *testing.T) {
|
||||||
|
setRequiredEnv(t)
|
||||||
|
t.Setenv("GENIUSRUN_FRONTEND_URL", "http://localhost:5173/")
|
||||||
|
|
||||||
|
cfg, err := Load()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Load: %v", err)
|
||||||
|
}
|
||||||
|
if cfg.FrontendURL != "http://localhost:5173" {
|
||||||
|
t.Errorf("FrontendURL = %q, want http://localhost:5173 (trailing slash trimmed)", cfg.FrontendURL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestLoad_CustomRoleAndDuration(t *testing.T) {
|
func TestLoad_CustomRoleAndDuration(t *testing.T) {
|
||||||
setRequiredEnv(t)
|
setRequiredEnv(t)
|
||||||
t.Setenv("GENIUSRUN_OIDC_REQUIRED_ROLE", "admin")
|
t.Setenv("GENIUSRUN_OIDC_REQUIRED_ROLE", "admin")
|
||||||
|
|||||||
Reference in New Issue
Block a user