mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2025-01-02 05:38:43 +00:00
Pass netrc data to external config service request (#2310)
Co-authored-by: Anbraten <anton@ju60.de>
This commit is contained in:
parent
06d1f3c92e
commit
09624aa286
7 changed files with 33 additions and 10 deletions
docs/docs/30-administration
server
api
forge
pipeline
plugins/config
|
@ -7,6 +7,10 @@ Every request sent by Woodpecker is signed using a [http-signature](https://data
|
|||
|
||||
A simplistic example configuration service can be found here: [https://github.com/woodpecker-ci/example-config-service](https://github.com/woodpecker-ci/example-config-service)
|
||||
|
||||
:::warning
|
||||
You need to trust the external config service as it is getting secret information about the repository and pipeline and has the ability to change pipeline configs that could run malicious tasks.
|
||||
:::
|
||||
|
||||
## Config
|
||||
|
||||
```shell
|
||||
|
|
|
@ -453,7 +453,12 @@ func PostPipeline(c *gin.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
newpipeline, err := pipeline.Restart(c, _store, pl, user, repo, envs)
|
||||
netrc, err := server.Config.Services.Forge.Netrc(user, repo)
|
||||
if err != nil {
|
||||
handlePipelineErr(c, err)
|
||||
}
|
||||
|
||||
newpipeline, err := pipeline.Restart(c, _store, pl, user, repo, envs, netrc)
|
||||
if err != nil {
|
||||
handlePipelineErr(c, err)
|
||||
} else {
|
||||
|
|
|
@ -74,10 +74,15 @@ func (cf *configFetcher) Fetch(ctx context.Context) (files []*types.FileMeta, er
|
|||
defer cancel() // ok here as we only try http fetching once, returning on fail and success
|
||||
|
||||
log.Trace().Msgf("ConfigFetch[%s]: getting config from external http service", cf.repo.FullName)
|
||||
newConfigs, useOld, err := cf.configExtension.FetchConfig(fetchCtx, cf.repo, cf.pipeline, files)
|
||||
netrc, err := cf.forge.Netrc(cf.user, cf.repo)
|
||||
if err != nil {
|
||||
log.Error().Msg("Got error " + err.Error())
|
||||
return nil, fmt.Errorf("On Fetching config via http : %w", err)
|
||||
return nil, fmt.Errorf("could not get Netrc data from forge: %w", err)
|
||||
}
|
||||
|
||||
newConfigs, useOld, err := cf.configExtension.FetchConfig(fetchCtx, cf.repo, cf.pipeline, files, netrc)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("could not fetch config via http")
|
||||
return nil, fmt.Errorf("could not fetch config via http: %w", err)
|
||||
}
|
||||
|
||||
if !useOld {
|
||||
|
@ -109,7 +114,7 @@ func (cf *configFetcher) fetch(c context.Context, timeout time.Duration, config
|
|||
return nil, fmt.Errorf("user defined config '%s' not found: %w", config, err)
|
||||
}
|
||||
|
||||
log.Trace().Msgf("ConfigFetch[%s]: user did not defined own config, following default procedure", cf.repo.FullName)
|
||||
log.Trace().Msgf("ConfigFetch[%s]: user did not define own config, following default procedure", cf.repo.FullName)
|
||||
// for the order see shared/constants/constants.go
|
||||
fileMeta, err := cf.getFirstAvailableConfig(ctx, constant.DefaultConfigOrder[:], false)
|
||||
if err == nil {
|
||||
|
|
|
@ -519,6 +519,8 @@ func TestFetchFromConfigService(t *testing.T) {
|
|||
f.On("File", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("File not found"))
|
||||
f.On("Dir", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("Directory not found"))
|
||||
|
||||
f.On("Netrc", mock.Anything, mock.Anything).Return(&model.Netrc{Machine: "mock", Login: "mock", Password: "mock"}, nil)
|
||||
|
||||
configFetcher := forge.NewConfigFetcher(
|
||||
f,
|
||||
time.Second*3,
|
||||
|
|
|
@ -30,7 +30,7 @@ import (
|
|||
)
|
||||
|
||||
// Restart a pipeline by creating a new one out of the old and start it
|
||||
func Restart(ctx context.Context, store store.Store, lastPipeline *model.Pipeline, user *model.User, repo *model.Repo, envs map[string]string) (*model.Pipeline, error) {
|
||||
func Restart(ctx context.Context, store store.Store, lastPipeline *model.Pipeline, user *model.User, repo *model.Repo, envs map[string]string, netrc *model.Netrc) (*model.Pipeline, error) {
|
||||
switch lastPipeline.Status {
|
||||
case model.StatusDeclined,
|
||||
model.StatusBlocked:
|
||||
|
@ -58,7 +58,7 @@ func Restart(ctx context.Context, store store.Store, lastPipeline *model.Pipelin
|
|||
currentFileMeta[i] = &forge_types.FileMeta{Name: cfg.Name, Data: cfg.Data}
|
||||
}
|
||||
|
||||
newConfig, useOld, err := server.Config.Services.ConfigService.FetchConfig(ctx, repo, lastPipeline, currentFileMeta)
|
||||
newConfig, useOld, err := server.Config.Services.ConfigService.FetchConfig(ctx, repo, lastPipeline, currentFileMeta, netrc)
|
||||
if err != nil {
|
||||
return nil, &ErrBadRequest{
|
||||
Msg: fmt.Sprintf("On fetching external pipeline config: %s", err),
|
||||
|
|
|
@ -23,5 +23,5 @@ import (
|
|||
|
||||
type Extension interface {
|
||||
IsConfigured() bool
|
||||
FetchConfig(ctx context.Context, repo *model.Repo, pipeline *model.Pipeline, currentFileMeta []*forge_types.FileMeta) (configData []*forge_types.FileMeta, useOld bool, err error)
|
||||
FetchConfig(ctx context.Context, repo *model.Repo, pipeline *model.Pipeline, currentFileMeta []*forge_types.FileMeta, netrc *model.Netrc) (configData []*forge_types.FileMeta, useOld bool, err error)
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ type requestStructure struct {
|
|||
Repo *model.Repo `json:"repo"`
|
||||
Pipeline *model.Pipeline `json:"pipeline"`
|
||||
Configuration []*config `json:"configs"`
|
||||
Netrc *model.Netrc `json:"netrc"`
|
||||
}
|
||||
|
||||
type responseStructure struct {
|
||||
|
@ -53,14 +54,20 @@ func (cp *http) IsConfigured() bool {
|
|||
return cp.endpoint != ""
|
||||
}
|
||||
|
||||
func (cp *http) FetchConfig(ctx context.Context, repo *model.Repo, pipeline *model.Pipeline, currentFileMeta []*forge_types.FileMeta) (configData []*forge_types.FileMeta, useOld bool, err error) {
|
||||
func (cp *http) FetchConfig(ctx context.Context, repo *model.Repo, pipeline *model.Pipeline, currentFileMeta []*forge_types.FileMeta, netrc *model.Netrc) (configData []*forge_types.FileMeta, useOld bool, err error) {
|
||||
currentConfigs := make([]*config, len(currentFileMeta))
|
||||
for i, pipe := range currentFileMeta {
|
||||
currentConfigs[i] = &config{Name: pipe.Name, Data: string(pipe.Data)}
|
||||
}
|
||||
|
||||
response := new(responseStructure)
|
||||
body := requestStructure{Repo: repo, Pipeline: pipeline, Configuration: currentConfigs}
|
||||
body := requestStructure{
|
||||
Repo: repo,
|
||||
Pipeline: pipeline,
|
||||
Configuration: currentConfigs,
|
||||
Netrc: netrc,
|
||||
}
|
||||
|
||||
status, err := utils.Send(ctx, "POST", cp.endpoint, cp.privateKey, body, response)
|
||||
if err != nil && status != 204 {
|
||||
return nil, false, fmt.Errorf("Failed to fetch config via http (%d) %w", status, err)
|
||||
|
|
Loading…
Reference in a new issue