Skip to content

Commit

Permalink
Add checks to determine if a user can trigger jobs
Browse files Browse the repository at this point in the history
  • Loading branch information
mirandachrist committed Jun 27, 2019
1 parent e5a3278 commit b4fb020
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 18 deletions.
41 changes: 34 additions & 7 deletions prow/cmd/deck/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ func prodOnlyMain(cfg config.Getter, o options, mux *http.ServeMux) *http.ServeM
mux.Handle("/prowjobs.js", gziphandler.GzipHandler(handleProwJobs(ja)))
mux.Handle("/badge.svg", gziphandler.GzipHandler(handleBadge(ja)))
mux.Handle("/log", gziphandler.GzipHandler(handleLog(ja)))
mux.Handle("/rerun", gziphandler.GzipHandler(handleRerun(prowJobClient, o.rerunCreatesJob)))
mux.Handle("/rerun", gziphandler.GzipHandler(handleRerun(prowJobClient, o.rerunCreatesJob, cfg)))
mux.Handle("/prowjob", gziphandler.GzipHandler(handleProwJob(prowJobClient)))

if o.spyglass {
Expand Down Expand Up @@ -1150,7 +1150,22 @@ func handleProwJob(prowJobClient prowv1.ProwJobInterface) http.HandlerFunc {
}
}

func handleRerun(prowJobClient prowv1.ProwJobInterface, createProwJob bool) http.HandlerFunc {
// canTriggerJob determines whether the given user can trigger any job.
func canTriggerJob(user string, cfg config.Getter) bool {
if cfg().Deck.RerunAuthConfig.AllowAnyone {
return true
}
if cfg().Deck.RerunAuthConfig.AuthorizedUsers != nil {
for _, s := range cfg().Deck.RerunAuthConfig.AuthorizedUsers {
if user == s {
return true
}
}
}
return false
}

func handleRerun(prowJobClient prowv1.ProwJobInterface, createProwJob bool, cfg config.Getter) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
name := r.URL.Query().Get("prowjob")
if name == "" {
Expand All @@ -1177,13 +1192,25 @@ func handleRerun(prowJobClient prowv1.ProwJobInterface, createProwJob bool) http
http.Error(w, "request must be of type POST", http.StatusMethodNotAllowed)
return
}
if _, err := prowJobClient.Create(&newPJ); err != nil {
logrus.WithError(err).Error("Error creating job")
http.Error(w, fmt.Sprintf("Error creating job: %v", err), http.StatusInternalServerError)
githubCookie, err := r.Cookie("github_login")
if err == http.ErrNoCookie {
http.Redirect(w, r, "/github-login", http.StatusFound)
} else if err != nil {
http.Error(w, fmt.Sprintf("Error retrieving GitHub cookie: %v", err), http.StatusInternalServerError)
return
}
if canTriggerJob(githubCookie.Value, cfg) {
if _, err := prowJobClient.Create(&newPJ); err != nil {
logrus.WithError(err).Error("Error creating job")
http.Error(w, fmt.Sprintf("Error creating job: %v", err), http.StatusInternalServerError)
return
}
http.Redirect(w, r, "/?rerun=success", http.StatusFound)
return
} else {
http.Redirect(w, r, "/?rerun=denied", http.StatusFound)
return
}
w.WriteHeader(http.StatusNoContent)
return
}
b, err := yaml.Marshal(&newPJ)
if err != nil {
Expand Down
62 changes: 53 additions & 9 deletions prow/cmd/deck/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,15 +258,43 @@ func TestProwJob(t *testing.T) {
func TestRerun(t *testing.T) {
testCases := []struct {
name string
login string
allowAnyone bool
rerunCreatesJob bool
shouldCreateProwjob bool
httpCode int
}{
{
name: "Handler returns ProwJob",
login: "hello",
allowAnyone: false,
rerunCreatesJob: true,
shouldCreateProwjob: true,
httpCode: http.StatusFound,
},
{
name: "User not authorized to create prow job",
login: "malicious",
allowAnyone: false,
rerunCreatesJob: true,
shouldCreateProwjob: false,
httpCode: http.StatusFound,
},
{
name: "RerunCreatesJob set to false, should not create prow job",
login: "hello",
allowAnyone: true,
rerunCreatesJob: false,
shouldCreateProwjob: false,
httpCode: http.StatusOK,
},
{
name: "Handler creates ProwJob",
name: "Allow anyone set to true, creates job",
login: "ugh",
allowAnyone: true,
rerunCreatesJob: true,
shouldCreateProwjob: true,
httpCode: http.StatusFound,
},
}

Expand All @@ -292,18 +320,37 @@ func TestRerun(t *testing.T) {
State: prowapi.PendingState,
},
})
handler := handleRerun(fakeProwJobClient.ProwV1().ProwJobs("prowjobs"), tc.shouldCreateProwjob)
configGetter := func() *config.Config {
return &config.Config{
ProwConfig: config.ProwConfig{
Deck: config.Deck{
RerunAuthConfig: config.RerunAuthConfig{
AllowAnyone: tc.allowAnyone,
AuthorizedUsers: []string{"hello", "world"},
},
},
},
}
}
handler := handleRerun(fakeProwJobClient.ProwV1().ProwJobs("prowjobs"), tc.rerunCreatesJob, configGetter)
req, err := http.NewRequest(http.MethodPost, "/rerun?prowjob=wowsuch", nil)
req.AddCookie(&http.Cookie{
Name: "github_login",
Value: tc.login,
Path: "/",
Expires: time.Now().Add(time.Hour * 24 * 30),
Secure: true,
})
if err != nil {
t.Fatalf("Error making request: %v", err)
}
rr := httptest.NewRecorder()
handler.ServeHTTP(rr, req)
if rr.Code != tc.httpCode {
t.Fatalf("Bad error code: %d", rr.Code)
}

if tc.shouldCreateProwjob {
if rr.Code != http.StatusNoContent {
t.Fatalf("Unexpected http status code: %d, expected 204", rr.Code)
}
pjs, err := fakeProwJobClient.ProwV1().ProwJobs("prowjobs").List(metav1.ListOptions{})
if err != nil {
t.Fatalf("failed to list prowjobs: %v", err)
Expand All @@ -312,10 +359,7 @@ func TestRerun(t *testing.T) {
t.Errorf("expected to get two prowjobs, got %d", numPJs)
}

} else {
if rr.Code != http.StatusOK {
t.Fatalf("Bad error code: %d", rr.Code)
}
} else if !tc.rerunCreatesJob {
resp := rr.Result()
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
Expand Down
10 changes: 8 additions & 2 deletions prow/cmd/deck/static/prow/prow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -650,7 +650,13 @@ function redraw(fz: FuzzySearch): void {
max = 2 * 3600;
}
drawJobHistogram(totalJob, jobHistogram, now - (12 * 3600), now, max);
if (rerunStatus != null) {
if (rerunStatus === "denied") {
modal.style.display = "block";
rerunCommand.innerHTML = `You don't have permission to rerun that job. Try asking @cjwagner.`;
} else if (rerunStatus === "success") {
modal.style.display = "block";
rerunCommand.innerHTML = `Job successfully triggered`;
} else if (rerunStatus != null) {
modal.style.display = "block";
rerunCommand.innerHTML = `Nice try! The direct rerun feature hasn't been implemented yet, so that button does nothing.`;
}
Expand All @@ -671,7 +677,7 @@ function createRerunCell(modal: HTMLElement, rerunElement: HTMLElement, prowjob:
copyButton.innerHTML = "<i class='material-icons state triggered' style='color: gray'>file_copy</i>";
rerunElement.appendChild(copyButton);
const runButton = document.createElement('a');
runButton.innerHTML = "<button class='mdl-button mdl-js-button'>Run</button>";
runButton.innerHTML = "<button class='mdl-button mdl-js-button'>Rerun</button>";
if (login === "") {
runButton.href = `/github-login?dest=%2F?rerun=work_in_progress`;
} else {
Expand Down

0 comments on commit b4fb020

Please sign in to comment.