diff --git a/models/actions/runner_test.go b/models/actions/runner_test.go index 1916c35a76..f6d6bd5d23 100644 --- a/models/actions/runner_test.go +++ b/models/actions/runner_test.go @@ -140,3 +140,98 @@ func TestDeleteOfflineRunnersErrorOnInvalidOlderThanValue(t *testing.T) { defer timeutil.MockUnset() require.Error(t, DeleteOfflineRunners(db.DefaultContext, timeutil.TimeStampNow(), false)) } + +func TestRunnerEditable(t *testing.T) { + testCases := []struct { + name string + runner *ActionRunner + ownerID int64 + repoID int64 + editable bool + }{ + { + name: "admin-can-edit-global-runner", + runner: &ActionRunner{Name: "global-runner", OwnerID: 0, RepoID: 0}, + ownerID: 0, + repoID: 0, + editable: true, + }, + { + name: "admin-can-edit-user-runner", + runner: &ActionRunner{Name: "user-runner", OwnerID: 36, RepoID: 0}, + ownerID: 0, + repoID: 0, + editable: true, + }, + { + name: "admin-can-edit-repository-runner", + runner: &ActionRunner{Name: "user-runner", OwnerID: 0, RepoID: 110}, + ownerID: 0, + repoID: 0, + editable: true, + }, + { + name: "user-can-edit-its-runner", + runner: &ActionRunner{Name: "user-runner", OwnerID: 469, RepoID: 0}, + ownerID: 469, + repoID: 0, + editable: true, + }, + { + name: "user-cannot-edit-global-runner", + runner: &ActionRunner{Name: "global-runner", OwnerID: 0, RepoID: 0}, + ownerID: 469, + repoID: 0, + editable: false, + }, + { + name: "user-cannot-edit-other-users-runner", + runner: &ActionRunner{Name: "user-runner", OwnerID: 892, RepoID: 0}, + ownerID: 469, + repoID: 0, + editable: false, + }, + { + name: "user-cannot-edit-repo-runner", + runner: &ActionRunner{Name: "repo-runner", OwnerID: 0, RepoID: 151}, + ownerID: 469, + repoID: 0, + editable: false, + }, + { + name: "repo-can-edit-its-runner", + runner: &ActionRunner{Name: "repo-runner", OwnerID: 0, RepoID: 693}, + ownerID: 0, + repoID: 693, + editable: true, + }, + { + name: "repo-cannot-edit-other-repo-runner", + runner: &ActionRunner{Name: "repo-runner", OwnerID: 0, RepoID: 519}, + ownerID: 0, + repoID: 693, + editable: false, + }, + { + name: "repo-cannot-edit-global-runner", + runner: &ActionRunner{Name: "global-runner", OwnerID: 0, RepoID: 0}, + ownerID: 0, + repoID: 693, + editable: false, + }, + { + name: "repo-cannot-edit-user-runner", + runner: &ActionRunner{Name: "user-runner", OwnerID: 6, RepoID: 0}, + ownerID: 0, + repoID: 693, + editable: false, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + result := testCase.runner.Editable(testCase.ownerID, testCase.repoID) + assert.Equal(t, testCase.editable, result) + }) + } +} diff --git a/tests/integration/fixtures/TestRunnerVisibility/action_runner.yml b/tests/integration/fixtures/TestRunnerVisibility/action_runner.yml new file mode 100644 index 0000000000..a20840396a --- /dev/null +++ b/tests/integration/fixtures/TestRunnerVisibility/action_runner.yml @@ -0,0 +1,54 @@ +- id: 719931 + uuid: "8f940b0b-32a2-479a-9d48-06ab8d8a0b90" + name: "runner-1" + version: "dev" + owner_id: 3 + repo_id: 0 + description: "A superb runner" + agent_labels: ["debian", "gpu"] + deleted: 0 +- id: 719932 + uuid: "3a20ad8d-d5d6-4b7b-ba55-841ac8264c17" + name: "runner-2" + version: "11.3.1" + owner_id: 2 + repo_id: 0 + description: "An exclusive runner" + agent_labels: ["docker"] + deleted: 0 +- id: 719933 + uuid: "11c9a6da-0a92-46ea-a4f1-b6c98f8c781c" + name: "runner-3" + version: "11.3.1" + owner_id: 17 + repo_id: 0 + description: "Another fine runner" + agent_labels: ["fedora"] + deleted: 0 +- id: 719934 + uuid: "1ef59b64-93b7-4ad4-ade4-21ca13db49c0" + name: "runner-4" + version: "12.2.0" + owner_id: 0 + repo_id: 0 + description: "A runner for everyone" + agent_labels: ["docker"] + deleted: 0 +- id: 719935 + uuid: "69d29449-1de5-4d17-845d-e3ae11a04a1b" + name: "runner-5" + version: "12.0.0" + owner_id: 1 + repo_id: 0 + description: "" + agent_labels: ["debian"] + deleted: 0 +- id: 719936 + uuid: "9da25fbb-89a5-4520-a35a-d55fc94e4b76" + name: "runner-6" + version: "12.1.0" + owner_id: 0 + repo_id: 62 + description: "" + agent_labels: ["debian"] + deleted: 0 diff --git a/tests/integration/runner_test.go b/tests/integration/runner_test.go index 6ca5a818d4..3379331e84 100644 --- a/tests/integration/runner_test.go +++ b/tests/integration/runner_test.go @@ -121,3 +121,73 @@ func TestRunnerModification(t *testing.T) { }) }) } + +func TestRunnerVisibility(t *testing.T) { + defer unittest.OverrideFixtures("tests/integration/fixtures/TestRunnerVisibility")() + defer tests.PrepareTestEnv(t)() + + admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{IsAdmin: true}) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + + runnerOne := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunner{ID: 719931}) + runnerTwo := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunner{ID: 719932}) + runnerThree := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunner{ID: 719933}) + runnerFour := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunner{ID: 719934}) + runnerFive := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunner{ID: 719935}) + runnerSix := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunner{ID: 719936}) + + testCases := []struct { + name string + user *user_model.User + url string + expectedRunners []*actions_model.ActionRunner + unexpectedRunners []*actions_model.ActionRunner + }{ + { + name: "admin-sees-all", + user: admin, + url: "/admin/actions/runners", + expectedRunners: []*actions_model.ActionRunner{runnerOne, runnerTwo, runnerThree, runnerFour, runnerFive, runnerSix}, + unexpectedRunners: []*actions_model.ActionRunner{}, + }, + { + name: "user-sees-own-and-global", + user: user2, + url: "user/settings/actions/runners", + expectedRunners: []*actions_model.ActionRunner{runnerTwo, runnerFour}, + unexpectedRunners: []*actions_model.ActionRunner{runnerOne, runnerThree, runnerFive, runnerSix}, + }, + { + name: "org-sees-own-and-global", + user: user2, + url: "/org/org3/settings/actions/runners", + expectedRunners: []*actions_model.ActionRunner{runnerOne, runnerFour}, + unexpectedRunners: []*actions_model.ActionRunner{runnerTwo, runnerThree, runnerFive, runnerSix}, + }, + { + name: "user-repo-sees-own-and-users-and-global", + user: user2, + url: "/user2/test_workflows/settings/actions/runners", + expectedRunners: []*actions_model.ActionRunner{runnerTwo, runnerFour, runnerSix}, + unexpectedRunners: []*actions_model.ActionRunner{runnerOne, runnerThree, runnerFive}, + }, + } + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + session := loginUser(t, testCase.user.Name) + + request := NewRequest(t, "GET", testCase.url) + response := session.MakeRequest(t, request, http.StatusOK) + + htmlDoc := NewHTMLParser(t, response.Body) + for _, expectedRunner := range testCase.expectedRunners { + selector := fmt.Sprintf("td:contains('%s')", expectedRunner.Name) + assert.Equal(t, 1, htmlDoc.Find(selector).Length(), "runner '%s' could not be found", expectedRunner.Name) + } + for _, unexpectedRunner := range testCase.unexpectedRunners { + selector := fmt.Sprintf("td:contains('%s')", unexpectedRunner.Name) + assert.Zero(t, htmlDoc.Find(selector).Length(), "runner '%s' is unexpectedly present", unexpectedRunner.Name) + } + }) + } +}