From 2ecf7a03fce555719c60bddd7eddb89f41918888 Mon Sep 17 00:00:00 2001 From: Tom Kneiphof Date: Wed, 20 Sep 2023 12:05:25 -0400 Subject: [PATCH 1/6] Fix usage of RootPath --- server/api/badge.go | 2 +- server/api/repo.go | 18 ++++++++++-------- server/forge/common/status.go | 4 ++-- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/server/api/badge.go b/server/api/badge.go index 41f0b489426..8feb7b2a5c3 100644 --- a/server/api/badge.go +++ b/server/api/badge.go @@ -118,7 +118,7 @@ func GetCC(c *gin.Context) { return } - url := fmt.Sprintf("%s/%s/%d", server.Config.Server.Host, repo.FullName, pipelines[0].Number) + url := fmt.Sprintf("%s%s/%s/%d", server.Config.Server.Host, server.Config.Server.RootPath, repo.FullName, pipelines[0].Number) cc := ccmenu.New(repo, pipelines[0], url) c.XML(http.StatusOK, cc) } diff --git a/server/api/repo.go b/server/api/repo.go index fc92d17ccc3..ea0c578b7c6 100644 --- a/server/api/repo.go +++ b/server/api/repo.go @@ -112,9 +112,10 @@ func PostRepo(c *gin.Context) { return } + baseurl := server.Config.Server.WebhookHost + server.Config.Server.RootPath link := fmt.Sprintf( "%s/api/hook?access_token=%s", - server.Config.Server.WebhookHost, + baseurl, sig, ) @@ -389,7 +390,8 @@ func DeleteRepo(c *gin.Context) { } } - if err := server.Config.Services.Forge.Deactivate(c, user, repo, server.Config.Server.Host); err != nil { + baseurl := server.Config.Server.WebhookHost + server.Config.Server.RootPath + if err := server.Config.Services.Forge.Deactivate(c, user, repo, baseurl); err != nil { _ = c.AbortWithError(http.StatusInternalServerError, err) return } @@ -420,10 +422,10 @@ func RepairRepo(c *gin.Context) { } // reconstruct the link - host := server.Config.Server.WebhookHost + baseurl := server.Config.Server.WebhookHost + server.Config.Server.RootPath link := fmt.Sprintf( "%s/api/hook?access_token=%s", - host, + baseurl, sig, ) @@ -456,7 +458,7 @@ func RepairRepo(c *gin.Context) { return } - if err := forge.Deactivate(c, user, repo, host); err != nil { + if err := forge.Deactivate(c, user, repo, baseurl); err != nil { log.Trace().Err(err).Msgf("deactivate repo '%s' to repair failed", repo.FullName) } if err := forge.Activate(c, user, repo, link); err != nil { @@ -534,14 +536,14 @@ func MoveRepo(c *gin.Context) { } // reconstruct the link - host := server.Config.Server.Host + baseurl := server.Config.Server.WebhookHost + server.Config.Server.RootPath link := fmt.Sprintf( "%s/api/hook?access_token=%s", - host, + baseurl, sig, ) - if err := forge.Deactivate(c, user, repo, host); err != nil { + if err := forge.Deactivate(c, user, repo, baseurl); err != nil { log.Trace().Err(err).Msgf("deactivate repo '%s' for move to activate later, got an error", repo.FullName) } if err := forge.Activate(c, user, repo, link); err != nil { diff --git a/server/forge/common/status.go b/server/forge/common/status.go index cae222fbcc0..3f9961fab9d 100644 --- a/server/forge/common/status.go +++ b/server/forge/common/status.go @@ -74,8 +74,8 @@ func GetPipelineStatusDescription(status model.StatusValue) string { func GetPipelineStatusLink(repo *model.Repo, pipeline *model.Pipeline, workflow *model.Workflow) string { if workflow == nil { - return fmt.Sprintf("%s/repos/%d/pipeline/%d", server.Config.Server.Host, repo.ID, pipeline.Number) + return fmt.Sprintf("%s%s/repos/%d/pipeline/%d", server.Config.Server.Host, server.Config.Server.RootPath, repo.ID, pipeline.Number) } - return fmt.Sprintf("%s/repos/%d/pipeline/%d/%d", server.Config.Server.Host, repo.ID, pipeline.Number, workflow.PID) + return fmt.Sprintf("%s%s/repos/%d/pipeline/%d/%d", server.Config.Server.Host, server.Config.Server.RootPath, repo.ID, pipeline.Number, workflow.PID) } From 132e86eba4608ffb199191e95cc2cb5c44549a39 Mon Sep 17 00:00:00 2001 From: Tom Kneiphof Date: Thu, 21 Sep 2023 09:04:13 -0400 Subject: [PATCH 2/6] Don't use RootPath in conjunction with *Host --- server/api/badge.go | 2 +- server/api/repo.go | 19 +++++++++---------- server/forge/bitbucket/bitbucket.go | 2 +- server/forge/common/status.go | 4 ++-- server/forge/gitea/gitea.go | 2 +- server/forge/github/github.go | 4 ++-- server/forge/gitlab/gitlab.go | 2 +- 7 files changed, 17 insertions(+), 18 deletions(-) diff --git a/server/api/badge.go b/server/api/badge.go index 8feb7b2a5c3..41f0b489426 100644 --- a/server/api/badge.go +++ b/server/api/badge.go @@ -118,7 +118,7 @@ func GetCC(c *gin.Context) { return } - url := fmt.Sprintf("%s%s/%s/%d", server.Config.Server.Host, server.Config.Server.RootPath, repo.FullName, pipelines[0].Number) + url := fmt.Sprintf("%s/%s/%d", server.Config.Server.Host, repo.FullName, pipelines[0].Number) cc := ccmenu.New(repo, pipelines[0], url) c.XML(http.StatusOK, cc) } diff --git a/server/api/repo.go b/server/api/repo.go index ea0c578b7c6..1ad53c9e62f 100644 --- a/server/api/repo.go +++ b/server/api/repo.go @@ -112,10 +112,9 @@ func PostRepo(c *gin.Context) { return } - baseurl := server.Config.Server.WebhookHost + server.Config.Server.RootPath link := fmt.Sprintf( "%s/api/hook?access_token=%s", - baseurl, + server.Config.Server.WebhookHost, sig, ) @@ -390,8 +389,8 @@ func DeleteRepo(c *gin.Context) { } } - baseurl := server.Config.Server.WebhookHost + server.Config.Server.RootPath - if err := server.Config.Services.Forge.Deactivate(c, user, repo, baseurl); err != nil { + host := server.Config.Server.WebhookHost + if err := server.Config.Services.Forge.Deactivate(c, user, repo, host); err != nil { _ = c.AbortWithError(http.StatusInternalServerError, err) return } @@ -422,10 +421,10 @@ func RepairRepo(c *gin.Context) { } // reconstruct the link - baseurl := server.Config.Server.WebhookHost + server.Config.Server.RootPath + host := server.Config.Server.WebhookHost link := fmt.Sprintf( "%s/api/hook?access_token=%s", - baseurl, + host, sig, ) @@ -458,7 +457,7 @@ func RepairRepo(c *gin.Context) { return } - if err := forge.Deactivate(c, user, repo, baseurl); err != nil { + if err := forge.Deactivate(c, user, repo, host); err != nil { log.Trace().Err(err).Msgf("deactivate repo '%s' to repair failed", repo.FullName) } if err := forge.Activate(c, user, repo, link); err != nil { @@ -536,14 +535,14 @@ func MoveRepo(c *gin.Context) { } // reconstruct the link - baseurl := server.Config.Server.WebhookHost + server.Config.Server.RootPath + host := server.Config.Server.WebhookHost link := fmt.Sprintf( "%s/api/hook?access_token=%s", - baseurl, + host, sig, ) - if err := forge.Deactivate(c, user, repo, baseurl); err != nil { + if err := forge.Deactivate(c, user, repo, host); err != nil { log.Trace().Err(err).Msgf("deactivate repo '%s' for move to activate later, got an error", repo.FullName) } if err := forge.Activate(c, user, repo, link); err != nil { diff --git a/server/forge/bitbucket/bitbucket.go b/server/forge/bitbucket/bitbucket.go index 81b5e6a862c..a8e6ca3a873 100644 --- a/server/forge/bitbucket/bitbucket.go +++ b/server/forge/bitbucket/bitbucket.go @@ -421,7 +421,7 @@ func (c *config) newOAuth2Config() *oauth2.Config { AuthURL: fmt.Sprintf("%s/site/oauth2/authorize", c.url), TokenURL: fmt.Sprintf("%s/site/oauth2/access_token", c.url), }, - RedirectURL: fmt.Sprintf("%s%s/authorize", server.Config.Server.OAuthHost, server.Config.Server.RootPath), + RedirectURL: fmt.Sprintf("%s/authorize", server.Config.Server.OAuthHost), } } diff --git a/server/forge/common/status.go b/server/forge/common/status.go index 3f9961fab9d..cae222fbcc0 100644 --- a/server/forge/common/status.go +++ b/server/forge/common/status.go @@ -74,8 +74,8 @@ func GetPipelineStatusDescription(status model.StatusValue) string { func GetPipelineStatusLink(repo *model.Repo, pipeline *model.Pipeline, workflow *model.Workflow) string { if workflow == nil { - return fmt.Sprintf("%s%s/repos/%d/pipeline/%d", server.Config.Server.Host, server.Config.Server.RootPath, repo.ID, pipeline.Number) + return fmt.Sprintf("%s/repos/%d/pipeline/%d", server.Config.Server.Host, repo.ID, pipeline.Number) } - return fmt.Sprintf("%s%s/repos/%d/pipeline/%d/%d", server.Config.Server.Host, server.Config.Server.RootPath, repo.ID, pipeline.Number, workflow.PID) + return fmt.Sprintf("%s/repos/%d/pipeline/%d/%d", server.Config.Server.Host, repo.ID, pipeline.Number, workflow.PID) } diff --git a/server/forge/gitea/gitea.go b/server/forge/gitea/gitea.go index 4c60718ea1c..13f29c3249c 100644 --- a/server/forge/gitea/gitea.go +++ b/server/forge/gitea/gitea.go @@ -103,7 +103,7 @@ func (c *Gitea) oauth2Config(ctx context.Context) (*oauth2.Config, context.Conte AuthURL: fmt.Sprintf(authorizeTokenURL, c.url), TokenURL: fmt.Sprintf(accessTokenURL, c.url), }, - RedirectURL: fmt.Sprintf("%s%s/authorize", server.Config.Server.OAuthHost, server.Config.Server.RootPath), + RedirectURL: fmt.Sprintf("%s/authorize", server.Config.Server.OAuthHost), }, context.WithValue(ctx, oauth2.HTTPClient, &http.Client{Transport: &http.Transport{ diff --git a/server/forge/github/github.go b/server/forge/github/github.go index 48775add561..53c65bb684d 100644 --- a/server/forge/github/github.go +++ b/server/forge/github/github.go @@ -400,9 +400,9 @@ func (c *client) newConfig(req *http.Request) *oauth2.Config { intendedURL := req.URL.Query()["url"] if len(intendedURL) > 0 { - redirect = fmt.Sprintf("%s%s/authorize?url=%s", server.Config.Server.OAuthHost, server.Config.Server.RootPath, intendedURL[0]) + redirect = fmt.Sprintf("%s/authorize?url=%s", server.Config.Server.OAuthHost, intendedURL[0]) } else { - redirect = fmt.Sprintf("%s%s/authorize", server.Config.Server.OAuthHost, server.Config.Server.RootPath) + redirect = fmt.Sprintf("%s/authorize", server.Config.Server.OAuthHost) } return &oauth2.Config{ diff --git a/server/forge/gitlab/gitlab.go b/server/forge/gitlab/gitlab.go index c34b33dc7fe..ae25f6cf2e6 100644 --- a/server/forge/gitlab/gitlab.go +++ b/server/forge/gitlab/gitlab.go @@ -93,7 +93,7 @@ func (g *GitLab) oauth2Config(ctx context.Context) (*oauth2.Config, context.Cont TokenURL: fmt.Sprintf("%s/oauth/token", g.url), }, Scopes: []string{defaultScope}, - RedirectURL: fmt.Sprintf("%s%s/authorize", server.Config.Server.OAuthHost, server.Config.Server.RootPath), + RedirectURL: fmt.Sprintf("%s/authorize", server.Config.Server.OAuthHost), }, context.WithValue(ctx, oauth2.HTTPClient, &http.Client{Transport: &http.Transport{ From 715c6ed957b26dcc7a5d9d6ae975116b3e39ec1e Mon Sep 17 00:00:00 2001 From: Tom Kneiphof Date: Thu, 21 Sep 2023 09:45:20 -0400 Subject: [PATCH 3/6] Auto-detect RootPath --- cmd/server/server.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cmd/server/server.go b/cmd/server/server.go index 0753deee917..520340df2db 100644 --- a/cmd/server/server.go +++ b/cmd/server/server.go @@ -344,7 +344,13 @@ func setupEvilGlobals(c *cli.Context, v store.Store, f forge.Forge) { server.Config.Server.StatusContext = c.String("status-context") server.Config.Server.StatusContextFormat = c.String("status-context-format") server.Config.Server.SessionExpires = c.Duration("session-expires") - rootPath := strings.TrimSuffix(c.String("root-path"), "/") + rootPath := c.String("root-path") + if !c.IsSet("root-path") { + // Extract RootPath from Host... + u, _ := url.Parse(server.Config.Server.Host) + rootPath = u.Path + } + rootPath = strings.TrimSuffix(rootPath, "/") if rootPath != "" && !strings.HasPrefix(rootPath, "/") { rootPath = "/" + rootPath } From d3ab736fb3f8d041e1cc5c63689e048bd4aa339b Mon Sep 17 00:00:00 2001 From: Tom Kneiphof Date: Thu, 21 Sep 2023 09:58:40 -0400 Subject: [PATCH 4/6] Update documentation --- docs/docs/30-administration/00-setup.md | 1 - docs/docs/30-administration/10-server-config.md | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/docs/30-administration/00-setup.md b/docs/docs/30-administration/00-setup.md index c8f4276f5d3..662c3835b25 100644 --- a/docs/docs/30-administration/00-setup.md +++ b/docs/docs/30-administration/00-setup.md @@ -93,7 +93,6 @@ services: environment: - [...] + - WOODPECKER_HOST=${WOODPECKER_HOST} -+ - WOODPECKER_HOST=${WOODPECKER_HOST} ``` Woodpecker can also have its port's configured. It uses a separate port for gRPC and for HTTP. The agent performs gRPC calls and connects to the gRPC port. diff --git a/docs/docs/30-administration/10-server-config.md b/docs/docs/30-administration/10-server-config.md index 69121ad6632..33a010914f0 100644 --- a/docs/docs/30-administration/10-server-config.md +++ b/docs/docs/30-administration/10-server-config.md @@ -215,14 +215,14 @@ Disable colored debug output. ### `WOODPECKER_HOST` > Default: empty -Server fully qualified URL of the user-facing hostname. +Server fully qualified URL of the user-facing hostname and path prefix. -Example: `WOODPECKER_HOST=http://woodpecker.example.org` +Example: `WOODPECKER_HOST=http://woodpecker.example.org` or `WOODPECKER_HOST=http://example.org/woodpecker` ### `WOODPECKER_WEBHOOK_HOST` > Default: value from `WOODPECKER_HOST` config env -Server fully qualified URL of the Webhook-facing hostname. +Server fully qualified URL of the Webhook-facing hostname and path prefix. Example: `WOODPECKER_WEBHOOK_HOST=http://woodpecker-server.cicd.svc.cluster.local:8000` @@ -529,7 +529,7 @@ Specify a configuration service endpoint, see [Configuration Extension](./100-ex Specify how many seconds before timeout when fetching the Woodpecker configuration from a Forge ### `WOODPECKER_ROOT_PATH` -> Default: `` +> Default: extracted from `WOODPECKER_HOST` Server URL path prefix (used for statics loading when having a url path prefix), should start with `/` From b1580eaca4045cdd28c845fc3b33b35774cd4df4 Mon Sep 17 00:00:00 2001 From: Tom Kneiphof Date: Thu, 21 Sep 2023 20:55:08 +0200 Subject: [PATCH 5/6] Inline host variable Co-authored-by: qwerty287 <80460567+qwerty287@users.noreply.github.com> --- server/api/repo.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/server/api/repo.go b/server/api/repo.go index 1ad53c9e62f..e4ea4322c35 100644 --- a/server/api/repo.go +++ b/server/api/repo.go @@ -389,8 +389,7 @@ func DeleteRepo(c *gin.Context) { } } - host := server.Config.Server.WebhookHost - if err := server.Config.Services.Forge.Deactivate(c, user, repo, host); err != nil { + if err := server.Config.Services.Forge.Deactivate(c, user, repo, server.Config.Server.WebhookHost); err != nil { _ = c.AbortWithError(http.StatusInternalServerError, err) return } From 405d4360f499741f08c0489c7cadff8d5709be44 Mon Sep 17 00:00:00 2001 From: Tom Kneiphof Date: Thu, 21 Sep 2023 15:12:07 -0400 Subject: [PATCH 6/6] Clarify usage in cmd/server/flags.go --- cmd/server/flags.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/server/flags.go b/cmd/server/flags.go index d56899612c9..08cff584240 100644 --- a/cmd/server/flags.go +++ b/cmd/server/flags.go @@ -38,12 +38,12 @@ var flags = append([]cli.Flag{ &cli.StringFlag{ EnvVars: []string{"WOODPECKER_HOST"}, Name: "server-host", - Usage: "server fully qualified url (://)", + Usage: "server fully qualified url (://[/])", }, &cli.StringFlag{ EnvVars: []string{"WOODPECKER_WEBHOOK_HOST"}, Name: "server-webhook-host", - Usage: "server fully qualified url for forge's Webhooks (://)", + Usage: "server fully qualified url for forge's Webhooks (://[/])", }, &cli.StringFlag{ EnvVars: []string{"WOODPECKER_ROOT_PATH", "WOODPECKER_ROOT_URL"}, @@ -450,7 +450,7 @@ var flags = append([]cli.Flag{ &cli.StringFlag{ EnvVars: []string{"WOODPECKER_DEV_OAUTH_HOST"}, Name: "server-dev-oauth-host", - Usage: "server fully qualified url (://) used for oauth redirect (used for development)", + Usage: "server fully qualified url (://[/]) used for oauth redirect (used for development)", Value: "", Hidden: true, },