Skip to content

Commit

Permalink
fix(api): not allow to resynchronize pipeline on as code workflow #4806
Browse files Browse the repository at this point in the history
… (#4828)

Signed-off-by: Benjamin Coenen <5719034+bnjjj@users.noreply.github.com>
  • Loading branch information
bnjjj authored and yesnault committed Dec 17, 2019
1 parent c724a8e commit bea8a05
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 0 deletions.
8 changes: 8 additions & 0 deletions engine/api/workflow_run.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,14 @@ func (api *API) resyncWorkflowRunHandler() service.Handler {
return sdk.WrapError(err, "unable to load projet")
}

wf, err := workflow.Load(ctx, api.mustDB(), api.Cache, proj, name, deprecatedGetUser(ctx), workflow.LoadOptions{Minimal: true, DeepPipeline: false})
if err != nil {
return sdk.WrapError(err, "cannot load workflow %s/%s", key, name)
}
if wf.FromRepository != "" {
return sdk.ErrWorkflowAsCodeResync
}

run, err := workflow.LoadRun(ctx, api.mustDB(), key, name, number, workflow.LoadRunOptions{})
if err != nil {
return sdk.WrapError(err, "Unable to load last workflow run [%s/%d]", name, number)
Expand Down
156 changes: 156 additions & 0 deletions engine/api/workflow_run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -962,6 +962,162 @@ func Test_resyncWorkflowRunHandler(t *testing.T) {
assert.Equal(t, "New awesome stage", workflowRun.Workflow.Pipelines[pip.ID].Stages[0].Name)
}

func Test_resyncWorkflowRunHandlerError(t *testing.T) {
api, db, router, end := newTestAPI(t, bootstrap.InitiliazeDB)
defer end()
u, pass := assets.InsertAdminUser(db)
key := sdk.RandomString(10)
proj := assets.InsertTestProject(t, db, api.Cache, key, key, u)

//First pipeline
pip := sdk.Pipeline{
ProjectID: proj.ID,
ProjectKey: proj.Key,
Name: "pip1",
}
test.NoError(t, pipeline.InsertPipeline(db, api.Cache, proj, &pip, u))

s := sdk.NewStage("stage 1")
s.Enabled = true
s.PipelineID = pip.ID
pipeline.InsertStage(db, s)
j := &sdk.Job{
Enabled: true,
Action: sdk.Action{
Enabled: true,
},
}
pipeline.InsertJob(db, j, s.ID, &pip)
s.Jobs = append(s.Jobs, *j)

pip.Stages = append(pip.Stages, *s)

pipeline.InsertStage(db, s)
j = &sdk.Job{
Enabled: true,
Action: sdk.Action{
Enabled: true,
},
}
s.Jobs = append(s.Jobs, *j)

// Create Application
app := sdk.Application{
Name: sdk.RandomString(10),
ProjectID: proj.ID,
RepositoryFullname: "foo/myrepo",
VCSServer: "github",
}
assert.NoError(t, application.Insert(db, api.Cache, proj, &app, u))
assert.NoError(t, repositoriesmanager.InsertForApplication(db, &app, proj.Key))

w := sdk.Workflow{
Name: "test_1",
ProjectID: proj.ID,
ProjectKey: proj.Key,
FromRepository: "foo/myrepo",
WorkflowData: &sdk.WorkflowData{
Node: sdk.Node{
Name: "root",
Type: sdk.NodeTypePipeline,
Context: &sdk.NodeContext{
PipelineID: pip.ID,
ApplicationID: app.ID,
},
Triggers: []sdk.NodeTrigger{
{
ChildNode: sdk.Node{
Name: "child",
Type: sdk.NodeTypePipeline,
Context: &sdk.NodeContext{
PipelineID: pip.ID,
},
},
},
},
},
},
}

proj2, errP := project.Load(api.mustDB(), api.Cache, proj.Key, u, project.LoadOptions.WithPipelines, project.LoadOptions.WithGroups, project.LoadOptions.WithIntegrations)
test.NoError(t, errP)

test.NoError(t, workflow.Insert(db, api.Cache, &w, proj2, u))
w1, err := workflow.Load(context.TODO(), db, api.Cache, proj2, "test_1", u, workflow.LoadOptions{})
test.NoError(t, err)

//Prepare request
vars := map[string]string{
"key": proj.Key,
"permWorkflowName": w1.Name,
}
uri := router.GetRoute("POST", api.postWorkflowRunHandler, vars)
test.NotEmpty(t, uri)

opts := &sdk.WorkflowRunPostHandlerOption{
Manual: &sdk.WorkflowNodeRunManual{
Payload: map[string]string{
"git.branch": "master",
},
},
}
req := assets.NewAuthentifiedRequest(t, u, pass, "POST", uri, opts)

//Do the request
rec := httptest.NewRecorder()
router.Mux.ServeHTTP(rec, req)
assert.Equal(t, 202, rec.Code)

wr := &sdk.WorkflowRun{}
test.NoError(t, json.Unmarshal(rec.Body.Bytes(), wr))
assert.Equal(t, int64(1), wr.Number)

cpt := 0
for {
varsGet := map[string]string{
"key": proj.Key,
"permWorkflowName": w1.Name,
"number": "1",
}
uriGet := router.GetRoute("GET", api.getWorkflowRunHandler, varsGet)
reqGet := assets.NewAuthentifiedRequest(t, u, pass, "GET", uriGet, nil)
recGet := httptest.NewRecorder()
router.Mux.ServeHTTP(recGet, reqGet)

var wrGet sdk.WorkflowRun
assert.NoError(t, json.Unmarshal(recGet.Body.Bytes(), &wrGet))

if wrGet.Status != sdk.StatusPending.String() {
assert.Equal(t, sdk.StatusBuilding.String(), wrGet.Status)
break
}
t.Logf("workflow run response %+v\n", wrGet)
cpt++
if cpt > 10 {
break
}
}

pip.Stages[0].Name = "New awesome stage"
errS := pipeline.UpdateStage(db, &pip.Stages[0])
test.NoError(t, errS)

//Prepare request
vars = map[string]string{
"key": proj.Key,
"permWorkflowName": w1.Name,
"number": fmt.Sprintf("%d", wr.Number),
}
uri = router.GetRoute("POST", api.resyncWorkflowRunHandler, vars)
test.NotEmpty(t, uri)
req = assets.NewAuthentifiedRequest(t, u, pass, "POST", uri, nil)

//Do the request
rec = httptest.NewRecorder()
router.Mux.ServeHTTP(rec, req)
assert.Equal(t, 403, rec.Code)
}

func Test_postWorkflowRunHandler(t *testing.T) {
api, db, router, end := newTestAPI(t, bootstrap.InitiliazeDB)
defer end()
Expand Down
3 changes: 3 additions & 0 deletions sdk/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ var (
ErrBadBrokerConfiguration = Error{ID: 181, Status: http.StatusBadRequest}
ErrInvalidJobRequirementNetworkAccess = Error{ID: 182, Status: http.StatusBadRequest}
ErrInvalidWorkerModelNamePattern = Error{ID: 183, Status: http.StatusBadRequest}
ErrWorkflowAsCodeResync = Error{ID: 184, Status: http.StatusForbidden}
)

var errorsAmericanEnglish = map[int]string{
Expand Down Expand Up @@ -378,6 +379,7 @@ var errorsAmericanEnglish = map[int]string{
ErrIntegrationtNotFound.ID: "integration not found",
ErrBadBrokerConfiguration.ID: "Cannot connect to the broker of your event integration. Check your configuration",
ErrInvalidJobRequirementNetworkAccess.ID: "Invalid job requirement: network requirement must contains ':'. Example: golang.org:http, golang.org:443",
ErrWorkflowAsCodeResync.ID: "You cannot resynchronize an as-code workflow",
}

var errorsFrench = map[int]string{
Expand Down Expand Up @@ -557,6 +559,7 @@ var errorsFrench = map[int]string{
ErrEnvironmentNotFound.ID: "l'environnement n'existe pas",
ErrBadBrokerConfiguration.ID: "Impossible de se connecter à votre intégration de type évènement. Veuillez vérifier votre configuration",
ErrInvalidJobRequirementNetworkAccess.ID: "Pré-requis de job invalide: Le pré-requis network doit contenir un ':'. Exemple: golang.org:http, golang.org:443",
ErrWorkflowAsCodeResync.ID: "Impossible de resynchroniser un workflow en mode as-code",
}

var errorsLanguages = []map[int]string{
Expand Down

0 comments on commit bea8a05

Please sign in to comment.