mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 13:11:49 +00:00
chore: Remove global externalURL watcher (#64058)
This removes the need to register a global URL watcher. Instead, the conf package now returns a cached version, and also makes a copy of it so it's impossible to accidentally modify it. This makes it safe in non-cmd/frontend packages to use this. Test plan: All tests are still passing.
This commit is contained in:
parent
56467e3c48
commit
35dcea121f
@ -15,7 +15,6 @@ go_library(
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//cmd/frontend/backend",
|
||||
"//cmd/frontend/globals",
|
||||
"//cmd/frontend/internal/app/router",
|
||||
"//cmd/frontend/internal/app/ui/router",
|
||||
"//cmd/frontend/internal/auth/session",
|
||||
|
||||
@ -6,7 +6,6 @@ import (
|
||||
"github.com/sourcegraph/log"
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/backend"
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/globals"
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/internal/auth/userpasswd"
|
||||
"github.com/sourcegraph/sourcegraph/internal/conf"
|
||||
"github.com/sourcegraph/sourcegraph/internal/database"
|
||||
@ -41,6 +40,6 @@ func ResetPasswordURL(ctx context.Context, db database.DB, logger log.Logger, us
|
||||
return nil, errors.Wrap(err, msg)
|
||||
}
|
||||
|
||||
ru := globals.ExternalURL().ResolveReference(resetURL).String()
|
||||
ru := conf.ExternalURLParsed().ResolveReference(resetURL).String()
|
||||
return &ru, nil
|
||||
}
|
||||
|
||||
@ -21,7 +21,6 @@ go_library(
|
||||
importpath = "github.com/sourcegraph/sourcegraph/cmd/frontend/backend",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//cmd/frontend/globals",
|
||||
"//cmd/frontend/internal/app/router",
|
||||
"//cmd/frontend/internal/inventory",
|
||||
"//internal/actor",
|
||||
|
||||
@ -9,7 +9,6 @@ import (
|
||||
|
||||
"github.com/sourcegraph/log"
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/globals"
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/internal/app/router"
|
||||
"github.com/sourcegraph/sourcegraph/internal/actor"
|
||||
"github.com/sourcegraph/sourcegraph/internal/auth"
|
||||
@ -385,7 +384,7 @@ func (e *userEmails) SendUserEmailOnFieldUpdate(ctx context.Context, id int32, c
|
||||
Email: email,
|
||||
Change: change,
|
||||
Username: usr.Username,
|
||||
Host: globals.ExternalURL().Host,
|
||||
Host: conf.ExternalURLParsed().Host,
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -432,7 +431,7 @@ func (e *userEmails) SendUserEmailOnAccessTokenChange(ctx context.Context, id in
|
||||
Email: email,
|
||||
TokenName: tokenName,
|
||||
Username: usr.Username,
|
||||
Host: globals.ExternalURL().Host,
|
||||
Host: conf.ExternalURLParsed().Host,
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -572,11 +571,11 @@ func SendUserEmailVerificationEmail(ctx context.Context, username, email, code s
|
||||
Host string
|
||||
}{
|
||||
Username: username,
|
||||
URL: globals.ExternalURL().ResolveReference(&url.URL{
|
||||
URL: conf.ExternalURLParsed().ResolveReference(&url.URL{
|
||||
Path: verifyEmailPath.Path,
|
||||
RawQuery: q.Encode(),
|
||||
}).String(),
|
||||
Host: globals.ExternalURL().Host,
|
||||
Host: conf.ExternalURLParsed().Host,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
9
cmd/frontend/external/globals/BUILD.bazel
vendored
9
cmd/frontend/external/globals/BUILD.bazel
vendored
@ -1,9 +0,0 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "globals",
|
||||
srcs = ["globals.go"],
|
||||
importpath = "github.com/sourcegraph/sourcegraph/cmd/frontend/external/globals",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["//cmd/frontend/globals"],
|
||||
)
|
||||
13
cmd/frontend/external/globals/globals.go
vendored
13
cmd/frontend/external/globals/globals.go
vendored
@ -1,13 +0,0 @@
|
||||
// Package globals exports symbols from frontend/globals. See the parent
|
||||
// package godoc for more information.
|
||||
package globals
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/globals"
|
||||
)
|
||||
|
||||
func ExternalURL() *url.URL {
|
||||
return globals.ExternalURL()
|
||||
}
|
||||
@ -5,8 +5,5 @@ go_library(
|
||||
srcs = ["globals.go"],
|
||||
importpath = "github.com/sourcegraph/sourcegraph/cmd/frontend/globals",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//internal/conf",
|
||||
"@com_github_inconshreveable_log15//:log15",
|
||||
],
|
||||
deps = ["//internal/conf"],
|
||||
)
|
||||
|
||||
@ -2,69 +2,9 @@
|
||||
package globals
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"reflect"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/inconshreveable/log15" //nolint:logging // TODO move all logging to sourcegraph/log //nolint:go
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/internal/conf"
|
||||
)
|
||||
|
||||
var defaultExternalURL = &url.URL{
|
||||
Scheme: "http",
|
||||
Host: "example.com",
|
||||
}
|
||||
|
||||
var externalURL = func() atomic.Value {
|
||||
var v atomic.Value
|
||||
v.Store(defaultExternalURL)
|
||||
return v
|
||||
}()
|
||||
|
||||
var watchExternalURLOnce sync.Once
|
||||
|
||||
// WatchExternalURL watches for changes in the `externalURL` site configuration
|
||||
// so that changes are reflected in what is returned by the ExternalURL function.
|
||||
func WatchExternalURL() {
|
||||
watchExternalURLOnce.Do(func() {
|
||||
conf.Watch(func() {
|
||||
after := defaultExternalURL
|
||||
if val := conf.Get().ExternalURL; val != "" {
|
||||
var err error
|
||||
if after, err = url.Parse(val); err != nil {
|
||||
log15.Error("globals.ExternalURL", "value", val, "error", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if before := ExternalURL(); !reflect.DeepEqual(before, after) {
|
||||
SetExternalURL(after)
|
||||
if before.Host != "example.com" {
|
||||
log15.Info(
|
||||
"globals.ExternalURL",
|
||||
"updated", true,
|
||||
"before", before,
|
||||
"after", after,
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// ExternalURL returns the fully-resolved, externally accessible frontend URL.
|
||||
// Callers must not mutate the returned pointer.
|
||||
func ExternalURL() *url.URL {
|
||||
return externalURL.Load().(*url.URL)
|
||||
}
|
||||
|
||||
// SetExternalURL sets the fully-resolved, externally accessible frontend URL.
|
||||
func SetExternalURL(u *url.URL) {
|
||||
externalURL.Store(u)
|
||||
}
|
||||
|
||||
// ConfigurationServerFrontendOnly provides the contents of the site configuration
|
||||
// to other services and manages modifications to it.
|
||||
//
|
||||
|
||||
@ -16,7 +16,6 @@ import (
|
||||
"github.com/inconshreveable/log15" //nolint:logging // TODO move all logging to sourcegraph/log
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/globals"
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/graphqlbackend/externallink"
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/internal/cloneurls"
|
||||
"github.com/sourcegraph/sourcegraph/internal/api"
|
||||
@ -418,7 +417,7 @@ func (r *GitTreeEntryResolver) ExternalURLs(ctx context.Context) ([]*externallin
|
||||
}
|
||||
|
||||
func (r *GitTreeEntryResolver) RawZipArchiveURL() string {
|
||||
return globals.ExternalURL().ResolveReference(&url.URL{
|
||||
return conf.ExternalURLParsed().ResolveReference(&url.URL{
|
||||
Path: path.Join(r.Repository().URL(), "-/raw/", r.Path()),
|
||||
RawQuery: "format=zip",
|
||||
}).String()
|
||||
|
||||
@ -14,7 +14,6 @@ import (
|
||||
"github.com/graph-gophers/graphql-go"
|
||||
"github.com/graph-gophers/graphql-go/relay"
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/globals"
|
||||
sgactor "github.com/sourcegraph/sourcegraph/internal/actor"
|
||||
"github.com/sourcegraph/sourcegraph/internal/auth"
|
||||
"github.com/sourcegraph/sourcegraph/internal/authz/permssync"
|
||||
@ -305,7 +304,7 @@ func orgInvitationURLLegacy(org *types.Org, relative bool) string {
|
||||
if relative {
|
||||
return path
|
||||
}
|
||||
return globals.ExternalURL().ResolveReference(&url.URL{Path: path}).String()
|
||||
return conf.ExternalURLParsed().ResolveReference(&url.URL{Path: path}).String()
|
||||
}
|
||||
|
||||
func orgInvitationURL(invitation database.OrgInvitation, relative bool) (string, error) {
|
||||
@ -320,7 +319,7 @@ func orgInvitationURL(invitation database.OrgInvitation, relative bool) (string,
|
||||
if relative {
|
||||
return path, nil
|
||||
}
|
||||
return globals.ExternalURL().ResolveReference(&url.URL{Path: path}).String(), nil
|
||||
return conf.ExternalURLParsed().ResolveReference(&url.URL{Path: path}).String(), nil
|
||||
}
|
||||
|
||||
func createInvitationJWT(orgID int32, invitationID int64, senderID int32, expiryTime time.Time) (string, error) {
|
||||
@ -331,7 +330,7 @@ func createInvitationJWT(orgID int32, invitationID int64, senderID int32, expiry
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS512, &orgInvitationClaims{
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
Issuer: globals.ExternalURL().String(),
|
||||
Issuer: conf.ExternalURLParsed().String(),
|
||||
ExpiresAt: jwt.NewNumericDate(expiryTime),
|
||||
Subject: strconv.FormatInt(int64(orgID), 10),
|
||||
},
|
||||
|
||||
@ -9,7 +9,6 @@ import (
|
||||
"github.com/sourcegraph/log"
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/backend"
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/globals"
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/internal/auth/userpasswd"
|
||||
"github.com/sourcegraph/sourcegraph/internal/auth"
|
||||
"github.com/sourcegraph/sourcegraph/internal/conf"
|
||||
@ -27,7 +26,7 @@ func (r *randomizeUserPasswordResult) ResetPasswordURL() *string {
|
||||
if r.resetURL == nil {
|
||||
return nil
|
||||
}
|
||||
urlStr := globals.ExternalURL().ResolveReference(r.resetURL).String()
|
||||
urlStr := conf.ExternalURLParsed().ResolveReference(r.resetURL).String()
|
||||
return &urlStr
|
||||
}
|
||||
|
||||
|
||||
@ -22,7 +22,6 @@ go_library(
|
||||
deps = [
|
||||
"//cmd/frontend/auth",
|
||||
"//cmd/frontend/backend",
|
||||
"//cmd/frontend/globals",
|
||||
"//cmd/frontend/internal/app/assetsutil",
|
||||
"//cmd/frontend/internal/app/debugproxies",
|
||||
"//cmd/frontend/internal/app/errorutil",
|
||||
|
||||
@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/sourcegraph/log"
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/globals"
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/internal/app/errorutil"
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/internal/app/router"
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/internal/app/ui"
|
||||
@ -24,7 +23,7 @@ import (
|
||||
// and sets the actor in the request context.
|
||||
func NewHandler(db database.DB, logger log.Logger) http.Handler {
|
||||
session.SetSessionStore(session.NewRedisStore(func() bool {
|
||||
return globals.ExternalURL().Scheme == "https"
|
||||
return conf.ExternalURLParsed().Scheme == "https"
|
||||
}))
|
||||
|
||||
logger = logger.Scoped("appHandler")
|
||||
|
||||
@ -276,7 +276,7 @@ func NewJSContextFromRequest(req *http.Request, db database.DB) JSContext {
|
||||
a := sgactor.FromContext(ctx)
|
||||
|
||||
headers := make(map[string]string)
|
||||
headers["x-sourcegraph-client"] = globals.ExternalURL().String()
|
||||
headers["x-sourcegraph-client"] = conf.ExternalURLParsed().String()
|
||||
headers["X-Requested-With"] = "Sourcegraph" // required for httpapi to use cookie auth
|
||||
|
||||
// Propagate Cache-Control no-cache and max-age=0 directives
|
||||
@ -381,7 +381,7 @@ func NewJSContextFromRequest(req *http.Request, db database.DB) JSContext {
|
||||
// authentication above, but do not include e.g. hard-coded secrets about
|
||||
// the server instance here as they would be sent to anonymous users.
|
||||
context := JSContext{
|
||||
ExternalURL: globals.ExternalURL().String(),
|
||||
ExternalURL: conf.ExternalURLParsed().String(),
|
||||
XHRHeaders: headers,
|
||||
UserAgentIsBot: isBot(req.UserAgent()),
|
||||
AssetsRoot: assetsutil.URL("").String(),
|
||||
|
||||
@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/inconshreveable/log15" //nolint:logging // TODO move all logging to sourcegraph/log
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/globals"
|
||||
"github.com/sourcegraph/sourcegraph/internal/conf"
|
||||
)
|
||||
|
||||
var openSearchDescription = template.Must(template.New("").Parse(`
|
||||
@ -26,7 +26,7 @@ func openSearch(w http.ResponseWriter, r *http.Request) {
|
||||
BaseURL string
|
||||
SearchURL string
|
||||
}
|
||||
externalURL := globals.ExternalURL()
|
||||
externalURL := conf.ExternalURLParsed()
|
||||
externalURLStr := externalURL.String()
|
||||
data := vars{
|
||||
BaseURL: externalURLStr,
|
||||
|
||||
@ -15,7 +15,6 @@ go_library(
|
||||
deps = [
|
||||
"//cmd/frontend/auth",
|
||||
"//cmd/frontend/external/session",
|
||||
"//cmd/frontend/globals",
|
||||
"//cmd/frontend/hubspot",
|
||||
"//cmd/frontend/internal/auth/providers",
|
||||
"//internal/actor",
|
||||
|
||||
@ -14,8 +14,8 @@ import (
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/external/session"
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/globals"
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/internal/auth/providers"
|
||||
"github.com/sourcegraph/sourcegraph/internal/conf"
|
||||
"github.com/sourcegraph/sourcegraph/internal/extsvc"
|
||||
"github.com/sourcegraph/sourcegraph/internal/extsvc/azuredevops"
|
||||
"github.com/sourcegraph/sourcegraph/internal/extsvc/bitbucketcloud"
|
||||
@ -263,7 +263,7 @@ func canRedirect(redirect string) bool {
|
||||
return false
|
||||
}
|
||||
// if we have a non-relative url, make sure it's the same host as the sourcegraph instance
|
||||
if redirectURL.Host != "" && redirectURL.Host != globals.ExternalURL().Host {
|
||||
if redirectURL.Host != "" && redirectURL.Host != conf.ExternalURLParsed().Host {
|
||||
return false
|
||||
}
|
||||
// TODO: do we want to exclude any internal paths here?
|
||||
|
||||
@ -14,7 +14,6 @@ go_library(
|
||||
visibility = ["//cmd/frontend:__subpackages__"],
|
||||
deps = [
|
||||
"//cmd/frontend/auth",
|
||||
"//cmd/frontend/external/globals",
|
||||
"//cmd/frontend/external/session",
|
||||
"//cmd/frontend/hubspot",
|
||||
"//cmd/frontend/hubspot/hubspotutil",
|
||||
|
||||
@ -11,8 +11,8 @@ import (
|
||||
"github.com/coreos/go-oidc"
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/external/globals"
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/internal/auth/providers"
|
||||
"github.com/sourcegraph/sourcegraph/internal/conf"
|
||||
"github.com/sourcegraph/sourcegraph/internal/extsvc"
|
||||
"github.com/sourcegraph/sourcegraph/lib/errors"
|
||||
"github.com/sourcegraph/sourcegraph/schema"
|
||||
@ -128,7 +128,7 @@ func (p *Provider) oauth2Config() *oauth2.Config {
|
||||
// It would be nice if this was "/.auth/openidconnect/callback" not "/.auth/callback", but
|
||||
// many instances have the "/.auth/callback" value hardcoded in their external auth
|
||||
// provider, so we can't change it easily
|
||||
RedirectURL: globals.ExternalURL().
|
||||
RedirectURL: conf.ExternalURLParsed().
|
||||
ResolveReference(&url.URL{Path: p.callbackUrl}).
|
||||
String(),
|
||||
|
||||
|
||||
@ -20,7 +20,6 @@ go_library(
|
||||
visibility = ["//cmd/frontend:__subpackages__"],
|
||||
deps = [
|
||||
"//cmd/frontend/auth",
|
||||
"//cmd/frontend/globals",
|
||||
"//cmd/frontend/internal/auth/scim/filter",
|
||||
"//cmd/frontend/internal/auth/userpasswd",
|
||||
"//internal/authz",
|
||||
|
||||
@ -13,7 +13,6 @@ import (
|
||||
"github.com/sourcegraph/log"
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/auth"
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/globals"
|
||||
"github.com/sourcegraph/sourcegraph/internal/authz"
|
||||
"github.com/sourcegraph/sourcegraph/internal/conf"
|
||||
"github.com/sourcegraph/sourcegraph/internal/database"
|
||||
@ -249,7 +248,7 @@ func (u *UserSCIMService) Create(ctx context.Context, attributes scim.ResourceAt
|
||||
// Attempt to send emails in the background.
|
||||
goroutine.Go(func() {
|
||||
_ = sendPasswordResetEmail(u.getLogger(), u.db, user, primaryEmail)
|
||||
_ = sendWelcomeEmail(primaryEmail, globals.ExternalURL().String(), u.getLogger())
|
||||
_ = sendWelcomeEmail(primaryEmail, conf.ExternalURLParsed().String(), u.getLogger())
|
||||
})
|
||||
|
||||
now := time.Now()
|
||||
|
||||
@ -22,7 +22,6 @@ go_library(
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//cmd/frontend/backend",
|
||||
"//cmd/frontend/globals",
|
||||
"//cmd/frontend/hubspot",
|
||||
"//cmd/frontend/hubspot/hubspotutil",
|
||||
"//cmd/frontend/internal/auth/providers",
|
||||
|
||||
@ -10,7 +10,6 @@ import (
|
||||
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/globals"
|
||||
"github.com/sourcegraph/sourcegraph/internal/conf"
|
||||
"github.com/sourcegraph/sourcegraph/internal/rcache"
|
||||
"github.com/sourcegraph/sourcegraph/internal/redispool"
|
||||
@ -124,7 +123,7 @@ func (s *lockoutStore) GenerateUnlockAccountURL(userID int32) (string, string, e
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS512, &unlockAccountClaims{
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
Issuer: globals.ExternalURL().String(),
|
||||
Issuer: conf.ExternalURLParsed().String(),
|
||||
ExpiresAt: jwt.NewNumericDate(expiryTime),
|
||||
Subject: strconv.FormatInt(int64(userID), 10),
|
||||
},
|
||||
@ -145,7 +144,7 @@ func (s *lockoutStore) GenerateUnlockAccountURL(userID int32) (string, string, e
|
||||
|
||||
path := fmt.Sprintf("/unlock-account/%s", tokenString)
|
||||
|
||||
return globals.ExternalURL().ResolveReference(&url.URL{Path: path}).String(), tokenString, nil
|
||||
return conf.ExternalURLParsed().ResolveReference(&url.URL{Path: path}).String(), tokenString, nil
|
||||
}
|
||||
|
||||
// take site config link expiry into account as well when setting unlock expiry
|
||||
|
||||
@ -9,7 +9,6 @@ import (
|
||||
"github.com/sourcegraph/log"
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/backend"
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/globals"
|
||||
"github.com/sourcegraph/sourcegraph/internal/actor"
|
||||
"github.com/sourcegraph/sourcegraph/internal/conf"
|
||||
"github.com/sourcegraph/sourcegraph/internal/cookie"
|
||||
@ -30,8 +29,8 @@ func SendResetPasswordURLEmail(ctx context.Context, email, username string, rese
|
||||
Template: emailTemplate,
|
||||
Data: SetPasswordEmailTemplateData{
|
||||
Username: username,
|
||||
URL: globals.ExternalURL().ResolveReference(resetURL).String(),
|
||||
Host: globals.ExternalURL().Host,
|
||||
URL: conf.ExternalURLParsed().ResolveReference(resetURL).String(),
|
||||
Host: conf.ExternalURLParsed().Host,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/backend"
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/globals"
|
||||
"github.com/sourcegraph/sourcegraph/internal/conf"
|
||||
"github.com/sourcegraph/sourcegraph/internal/database"
|
||||
"github.com/sourcegraph/sourcegraph/internal/txemail"
|
||||
@ -24,7 +23,7 @@ func HandleSetPasswordEmail(ctx context.Context, db database.DB, id int32, usern
|
||||
return "", errors.Wrap(err, "make password reset URL")
|
||||
}
|
||||
|
||||
shareableResetURL := globals.ExternalURL().ResolveReference(resetURL).String()
|
||||
shareableResetURL := conf.ExternalURLParsed().ResolveReference(resetURL).String()
|
||||
emailedResetURL := shareableResetURL
|
||||
|
||||
if !emailVerified {
|
||||
@ -32,7 +31,7 @@ func HandleSetPasswordEmail(ctx context.Context, db database.DB, id int32, usern
|
||||
if err != nil {
|
||||
return shareableResetURL, errors.Wrap(err, "attach email verification")
|
||||
}
|
||||
emailedResetURL = globals.ExternalURL().ResolveReference(newURL).String()
|
||||
emailedResetURL = conf.ExternalURLParsed().ResolveReference(newURL).String()
|
||||
}
|
||||
|
||||
// Configure the template
|
||||
@ -47,7 +46,7 @@ func HandleSetPasswordEmail(ctx context.Context, db database.DB, id int32, usern
|
||||
Data: SetPasswordEmailTemplateData{
|
||||
Username: username,
|
||||
URL: emailedResetURL,
|
||||
Host: globals.ExternalURL().Host,
|
||||
Host: conf.ExternalURLParsed().Host,
|
||||
},
|
||||
}); err != nil {
|
||||
return shareableResetURL, err
|
||||
|
||||
@ -40,7 +40,6 @@ go_library(
|
||||
visibility = ["//cmd/frontend:__subpackages__"],
|
||||
deps = [
|
||||
"//cmd/frontend/enterprise",
|
||||
"//cmd/frontend/globals",
|
||||
"//cmd/frontend/graphqlbackend",
|
||||
"//cmd/frontend/graphqlbackend/externallink",
|
||||
"//cmd/frontend/graphqlbackend/graphqlutil",
|
||||
@ -131,7 +130,6 @@ go_test(
|
||||
],
|
||||
deps = [
|
||||
"//cmd/frontend/backend",
|
||||
"//cmd/frontend/globals",
|
||||
"//cmd/frontend/graphqlbackend",
|
||||
"//cmd/frontend/graphqlbackend/externallink",
|
||||
"//cmd/frontend/internal/batches/resolvers/apitest",
|
||||
|
||||
@ -3,22 +3,21 @@ package resolvers
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/sourcegraph/log"
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/internal/githubapp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
ghauth "github.com/sourcegraph/sourcegraph/internal/github_apps/auth"
|
||||
|
||||
"github.com/graph-gophers/graphql-go"
|
||||
"github.com/graph-gophers/graphql-go/relay"
|
||||
"github.com/sourcegraph/log"
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/globals"
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/graphqlbackend"
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/internal/githubapp"
|
||||
btypes "github.com/sourcegraph/sourcegraph/internal/batches/types"
|
||||
"github.com/sourcegraph/sourcegraph/internal/conf"
|
||||
"github.com/sourcegraph/sourcegraph/internal/database"
|
||||
"github.com/sourcegraph/sourcegraph/internal/extsvc"
|
||||
"github.com/sourcegraph/sourcegraph/internal/extsvc/auth"
|
||||
ghauth "github.com/sourcegraph/sourcegraph/internal/github_apps/auth"
|
||||
ghastore "github.com/sourcegraph/sourcegraph/internal/github_apps/store"
|
||||
"github.com/sourcegraph/sourcegraph/internal/gqlutil"
|
||||
"github.com/sourcegraph/sourcegraph/internal/types"
|
||||
@ -67,7 +66,7 @@ func unmarshalBatchChangesCredentialID(id graphql.ID) (credentialID int64, isSit
|
||||
}
|
||||
|
||||
func commentSSHKey(ssh auth.AuthenticatorWithSSH) string {
|
||||
url := globals.ExternalURL()
|
||||
url := conf.ExternalURLParsed()
|
||||
if url != nil && url.Host != "" {
|
||||
return strings.TrimRight(ssh.SSHPublicKey(), "\n") + " Sourcegraph " + url.Host
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ import (
|
||||
"github.com/graph-gophers/graphql-go"
|
||||
"github.com/graph-gophers/graphql-go/relay"
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/globals"
|
||||
"github.com/sourcegraph/sourcegraph/internal/conf"
|
||||
"github.com/sourcegraph/sourcegraph/internal/extsvc/auth"
|
||||
)
|
||||
|
||||
@ -67,7 +67,7 @@ func TestUnmarshalBatchChangesCredentialID(t *testing.T) {
|
||||
func TestCommentSSHKey(t *testing.T) {
|
||||
publicKey := "public\n"
|
||||
sshKey := commentSSHKey(&auth.BasicAuthWithSSH{BasicAuth: auth.BasicAuth{Username: "foo", Password: "bar"}, PrivateKey: "private", PublicKey: publicKey, Passphrase: "pass"})
|
||||
expectedKey := "public Sourcegraph " + globals.ExternalURL().Host
|
||||
expectedKey := "public Sourcegraph " + conf.ExternalURLParsed().Host
|
||||
|
||||
if sshKey != expectedKey {
|
||||
t.Errorf("found wrong ssh key: want=%q, have=%q", expectedKey, sshKey)
|
||||
|
||||
@ -14,11 +14,11 @@ go_library(
|
||||
importpath = "github.com/sourcegraph/sourcegraph/cmd/frontend/internal/cli/middleware",
|
||||
visibility = ["//cmd/frontend:__subpackages__"],
|
||||
deps = [
|
||||
"//cmd/frontend/globals",
|
||||
"//cmd/frontend/internal/app/router",
|
||||
"//cmd/frontend/internal/app/ui",
|
||||
"//cmd/frontend/internal/app/ui/router",
|
||||
"//internal/actor",
|
||||
"//internal/conf",
|
||||
"//internal/dotcom",
|
||||
"//internal/env",
|
||||
"//internal/trace",
|
||||
|
||||
@ -7,7 +7,7 @@ import (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/globals"
|
||||
"github.com/sourcegraph/sourcegraph/internal/conf"
|
||||
"github.com/sourcegraph/sourcegraph/internal/trace"
|
||||
"github.com/sourcegraph/sourcegraph/lib/errors"
|
||||
)
|
||||
@ -61,7 +61,7 @@ func SourcegraphComGoGetHandler(next http.Handler) http.Handler {
|
||||
// It's a vanity import path that maps to "github.com/{sourcegraph,sqs}/*" clone URLs.
|
||||
pathElements := strings.Split(req.URL.Path[1:], "/")
|
||||
if len(pathElements) >= 2 && (pathElements[0] == "sourcegraph" || pathElements[0] == "sqs") {
|
||||
host := globals.ExternalURL().Host
|
||||
host := conf.ExternalURLParsed().Host
|
||||
|
||||
user := pathElements[0]
|
||||
repo := pathElements[1]
|
||||
|
||||
@ -204,8 +204,6 @@ func Main(ctx context.Context, observationCtx *observation.Context, ready servic
|
||||
return err
|
||||
}
|
||||
|
||||
globals.WatchExternalURL()
|
||||
|
||||
// Single shot
|
||||
goroutine.Go(func() { bg.CheckRedisCacheEvictionPolicy() })
|
||||
goroutine.Go(func() { bg.UpdatePermissions(ctx, logger, db) })
|
||||
@ -296,7 +294,7 @@ func Main(ctx context.Context, observationCtx *observation.Context, ready servic
|
||||
infos[i] = providerInfo{
|
||||
ServiceType: p.ServiceType(),
|
||||
ServiceID: p.ServiceID(),
|
||||
ExternalServiceURL: fmt.Sprintf("%s/site-admin/external-services/%s", globals.ExternalURL(), relay.MarshalID("ExternalService", id)),
|
||||
ExternalServiceURL: fmt.Sprintf("%s/site-admin/external-services/%s", conf.ExternalURLParsed(), relay.MarshalID("ExternalService", id)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -313,7 +311,7 @@ func Main(ctx context.Context, observationCtx *observation.Context, ready servic
|
||||
// This is not a log entry and is usually disabled
|
||||
println(fmt.Sprintf("\n\n%s\n\n", logoColor))
|
||||
}
|
||||
logger.Info(fmt.Sprintf("✱ Sourcegraph is ready at: %s", globals.ExternalURL()))
|
||||
logger.Info(fmt.Sprintf("✱ Sourcegraph is ready at: %s", conf.ExternalURLParsed()))
|
||||
ready()
|
||||
|
||||
return goroutine.MonitorBackgroundRoutines(context.Background(), routines...)
|
||||
|
||||
@ -39,9 +39,9 @@ go_test(
|
||||
"requires-network",
|
||||
],
|
||||
deps = [
|
||||
"//cmd/frontend/external/globals",
|
||||
"//cmd/frontend/webhooks",
|
||||
"//internal/api",
|
||||
"//internal/conf",
|
||||
"//internal/database",
|
||||
"//internal/database/dbmocks",
|
||||
"//internal/database/dbtest",
|
||||
|
||||
@ -22,9 +22,9 @@ import (
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/external/globals"
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/webhooks"
|
||||
"github.com/sourcegraph/sourcegraph/internal/api"
|
||||
"github.com/sourcegraph/sourcegraph/internal/conf"
|
||||
"github.com/sourcegraph/sourcegraph/internal/database"
|
||||
"github.com/sourcegraph/sourcegraph/internal/database/dbmocks"
|
||||
"github.com/sourcegraph/sourcegraph/internal/database/dbtest"
|
||||
@ -158,7 +158,7 @@ func TestGitHubHandler(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
targetURL := fmt.Sprintf("%s/github-webhooks", globals.ExternalURL())
|
||||
targetURL := fmt.Sprintf("%s/github-webhooks", conf.ExternalURLParsed())
|
||||
req, err := http.NewRequest("POST", targetURL, bytes.NewReader(payload))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@ -13,7 +13,6 @@ go_library(
|
||||
tags = [TAG_PLATFORM_SOURCE],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//cmd/frontend/globals",
|
||||
"//cmd/repo-updater/internal/gitserver",
|
||||
"//cmd/repo-updater/internal/purge",
|
||||
"//cmd/repo-updater/internal/repoupdater",
|
||||
|
||||
@ -17,7 +17,6 @@ import (
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"github.com/sourcegraph/log"
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/globals"
|
||||
repogitserver "github.com/sourcegraph/sourcegraph/cmd/repo-updater/internal/gitserver"
|
||||
"github.com/sourcegraph/sourcegraph/cmd/repo-updater/internal/purge"
|
||||
"github.com/sourcegraph/sourcegraph/cmd/repo-updater/internal/repoupdater"
|
||||
@ -118,7 +117,6 @@ func Main(ctx context.Context, observationCtx *observation.Context, ready servic
|
||||
server.ChangesetSyncRegistry = syncRegistry
|
||||
}
|
||||
|
||||
go globals.WatchExternalURL()
|
||||
go watchSyncer(ctx, logger, syncer, updateScheduler, server.ChangesetSyncRegistry)
|
||||
|
||||
routines := []goroutine.BackgroundRoutine{
|
||||
|
||||
@ -51,6 +51,7 @@ go_library(
|
||||
"@com_github_xeipuuv_gojsonschema//:gojsonschema",
|
||||
"@org_golang_google_grpc//codes",
|
||||
"@org_golang_google_grpc//status",
|
||||
"@org_uber_go_atomic//:atomic",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@ -2,12 +2,15 @@ package conf
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"log" //nolint:logging // TODO move all logging to sourcegraph/log
|
||||
stdlog "log" //nolint:logging // TODO move all logging to sourcegraph/log
|
||||
"net/url"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/cronexpr"
|
||||
"github.com/sourcegraph/log"
|
||||
"go.uber.org/atomic"
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/internal/completions/client/anthropic"
|
||||
"github.com/sourcegraph/sourcegraph/internal/completions/client/google"
|
||||
@ -28,7 +31,7 @@ const CodyGatewayProdEndpoint = "https://cody-gateway.sourcegraph.com"
|
||||
func init() {
|
||||
deployType := deploy.Type()
|
||||
if !deploy.IsValidDeployType(deployType) {
|
||||
log.Fatalf("The 'DEPLOY_TYPE' environment variable is invalid. Expected one of: %q, %q, %q, %q, %q, %q. Got: %q", deploy.Kubernetes, deploy.DockerCompose, deploy.PureDocker, deploy.SingleDocker, deploy.Dev, deploy.Helm, deployType)
|
||||
stdlog.Fatalf("The 'DEPLOY_TYPE' environment variable is invalid. Expected one of: %q, %q, %q, %q, %q, %q. Got: %q", deploy.Kubernetes, deploy.DockerCompose, deploy.PureDocker, deploy.SingleDocker, deploy.Dev, deploy.Helm, deployType)
|
||||
}
|
||||
|
||||
confdefaults.Default = defaultConfigForDeployment()
|
||||
@ -434,6 +437,62 @@ func ProductResearchPageEnabled() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
type lastParsedURLValue struct {
|
||||
url *url.URL
|
||||
confValue string
|
||||
}
|
||||
|
||||
var lastParsedURL *atomic.Pointer[lastParsedURLValue] = atomic.NewPointer(&lastParsedURLValue{
|
||||
url: &url.URL{
|
||||
Scheme: "http",
|
||||
Host: "example.com",
|
||||
},
|
||||
confValue: "",
|
||||
})
|
||||
|
||||
// ExternalURLParsed returns a parsed version of conf.ExternalURL().
|
||||
// This function is thread-safe and returns a copy of the cached parsed version
|
||||
// of the URL, so it is also safe to mutate.
|
||||
func ExternalURLParsed() *url.URL {
|
||||
// Note that we do NOT use a mutex here, and instead let callers parse the URL
|
||||
// simultaneously during the short period where the URL was changed but the new
|
||||
// parsed value has not yet been cached.
|
||||
// This eliminates the need to acquire a mutex entirely, and avoids potential costly
|
||||
// locking if many requests are served concurrently.
|
||||
urlString := ExternalURL()
|
||||
lastParsed := lastParsedURL.Load()
|
||||
clonedURL := cloneURL(lastParsed.url)
|
||||
if lastParsed.confValue != urlString {
|
||||
parsed, err := url.Parse(urlString)
|
||||
if err != nil {
|
||||
log.Scoped("conf.ExternalURL").Error("failed to parse external URL", log.Error(err), log.String("externalURL", urlString))
|
||||
return clonedURL
|
||||
}
|
||||
lastParsed = &lastParsedURLValue{
|
||||
url: parsed,
|
||||
confValue: urlString,
|
||||
}
|
||||
lastParsedURL.Store(lastParsed)
|
||||
clonedURL = cloneURL(parsed)
|
||||
}
|
||||
return clonedURL
|
||||
}
|
||||
|
||||
// cloneURL returns a copy of the URL. It is safe to mutate the returned URL.
|
||||
// This is copied from net/http/clone.go
|
||||
func cloneURL(u *url.URL) *url.URL {
|
||||
if u == nil {
|
||||
return nil
|
||||
}
|
||||
u2 := new(url.URL)
|
||||
*u2 = *u
|
||||
if u.User != nil {
|
||||
u2.User = new(url.Userinfo)
|
||||
*u2.User = *u.User
|
||||
}
|
||||
return u2
|
||||
}
|
||||
|
||||
func ExternalURL() string {
|
||||
return Get().ExternalURL
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ package conf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -1356,3 +1357,54 @@ func TestAccessTokensExpirationOptions(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExternalURLParsed(t *testing.T) {
|
||||
t.Run("Result is mutable", func(t *testing.T) {
|
||||
Mock(&Unified{SiteConfiguration: schema.SiteConfiguration{
|
||||
ExternalURL: "https://sourcegraph.com",
|
||||
}})
|
||||
t.Cleanup(func() { Mock(nil) })
|
||||
u := ExternalURLParsed()
|
||||
u.Scheme = "http"
|
||||
assert.Equal(t, "http://sourcegraph.com", u.String())
|
||||
u2 := ExternalURLParsed()
|
||||
assert.Equal(t, "https://sourcegraph.com", u2.String())
|
||||
Mock(&Unified{SiteConfiguration: schema.SiteConfiguration{
|
||||
ExternalURL: "https://sourcegraph.sourcegraph.com",
|
||||
}})
|
||||
assert.Equal(t, "http://sourcegraph.com", u.String())
|
||||
assert.Equal(t, "https://sourcegraph.com", u2.String())
|
||||
})
|
||||
t.Run("Concurrent access and updates are memory safe", func(t *testing.T) {
|
||||
Mock(&Unified{SiteConfiguration: schema.SiteConfiguration{
|
||||
ExternalURL: "https://host-0.sourcegraph.com",
|
||||
}})
|
||||
t.Cleanup(func() { Mock(nil) })
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for i := range 1000 {
|
||||
Mock(&Unified{SiteConfiguration: schema.SiteConfiguration{
|
||||
ExternalURL: fmt.Sprintf("https://host-%d.sourcegraph.com", i),
|
||||
}})
|
||||
// Allow some time for synchronization.
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for range 1000 {
|
||||
u := ExternalURLParsed()
|
||||
assert.Contains(t, u.Host, ".sourcegraph.com")
|
||||
// Allow some time for synchronization.
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
})
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ go_library(
|
||||
importpath = "github.com/sourcegraph/sourcegraph/internal/deviceid",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//cmd/frontend/globals",
|
||||
"//internal/conf",
|
||||
"//internal/cookie",
|
||||
"@com_github_google_uuid//:uuid",
|
||||
],
|
||||
|
||||
@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/cmd/frontend/globals"
|
||||
"github.com/sourcegraph/sourcegraph/internal/conf"
|
||||
"github.com/sourcegraph/sourcegraph/internal/cookie"
|
||||
)
|
||||
|
||||
@ -22,7 +22,7 @@ func Middleware(next http.Handler) http.Handler {
|
||||
Name: "sourcegraphDeviceId",
|
||||
Value: newDeviceId.String(),
|
||||
Expires: time.Now().AddDate(1, 0, 0),
|
||||
Secure: globals.ExternalURL().Scheme == "https",
|
||||
Secure: conf.ExternalURLParsed().Scheme == "https",
|
||||
Domain: r.URL.Host,
|
||||
})
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user