Skip to content
/ gitea Public
  • Sponsor go-gitea/gitea

  • Notifications You must be signed in to change notification settings
  • Fork 5.7k
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Actions Runner rest api #33873

Open
wants to merge 26 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c062f18
WIP ActionRunner Org + Repo Api
ChristopherHX Mar 2, 2025
e2d9774
fix null labels
ChristopherHX Mar 2, 2025
f37caab
fix removed runner could still be retrieved via get
ChristopherHX Mar 2, 2025
0655965
add swagger docu / fix build
ChristopherHX Mar 12, 2025
f1de208
add admin / user level + api add correct registration token endpoint
ChristopherHX Mar 13, 2025
a3b42a9
add tests
ChristopherHX Mar 13, 2025
7a75b1c
update date
ChristopherHX Mar 13, 2025
76c5505
fix lint
ChristopherHX Mar 13, 2025
93d464b
fix definition bug
ChristopherHX Mar 13, 2025
d6db24c
add org test
ChristopherHX Mar 13, 2025
6f8aaf6
fix mssql failure add token_hash
ChristopherHX Mar 13, 2025
1394ed7
Update models/actions/runner.go
ChristopherHX Mar 14, 2025
f581e49
Merge branch 'main' into runners-rest-api
ChristopherHX Mar 14, 2025
e95db5a
Merge branch 'main' into runners-rest-api
ChristopherHX Mar 14, 2025
82834ff
expose ephemeral flag of runners
ChristopherHX Mar 14, 2025
efd080e
add permission org test
ChristopherHX Mar 14, 2025
b8b96d0
add check runner conflict test
ChristopherHX Mar 14, 2025
dfbdec1
Remove OS field, not needed for my usecase
ChristopherHX Mar 14, 2025
f387363
swagger remove OS field
ChristopherHX Mar 14, 2025
ee066b6
format test
ChristopherHX Mar 14, 2025
cb8f30b
remove active runner deletion blocker
ChristopherHX Mar 16, 2025
3b38b05
Merge branch 'main' of https://github.com/go-gitea/gitea into runners…
ChristopherHX Mar 16, 2025
1eed2ec
Repo level tests
ChristopherHX Mar 17, 2025
e9a4ef9
Merge branch 'main' of https://github.com/go-gitea/gitea into runners…
ChristopherHX Mar 17, 2025
307b8e1
add missing fixture
ChristopherHX Mar 17, 2025
72e71c8
Merge branch 'main' of https://github.com/go-gitea/gitea into runners…
ChristopherHX Mar 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Repo level tests
ChristopherHX committed Mar 17, 2025
commit 1eed2ec2d5d8d2fe234da305f07156ef12751a87
140 changes: 140 additions & 0 deletions tests/integration/api_repo_runner_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package integration

import (
"fmt"
"net/http"
"testing"

actions_model "code.gitea.io/gitea/models/actions"
auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/tests"

"github.com/stretchr/testify/assert"
)

func TestAPIRunnerRepoApi(t *testing.T) {
defer tests.PrepareTestEnv(t)()
userUsername := "user2"
token := getUserToken(t, userUsername, auth_model.AccessTokenScopeWriteRepository)
req := NewRequest(t, "POST", "/api/v1/repos/user2/repo1/actions/runners/registration-token").AddTokenAuth(token)
tokenResp := MakeRequest(t, req, http.StatusOK)
var registrationToken struct {
Token string `json:"token"`
}
DecodeJSON(t, tokenResp, &registrationToken)
assert.NotEmpty(t, registrationToken.Token)

req = NewRequest(t, "GET", "/api/v1/repos/user2/repo1/actions/runners").AddTokenAuth(token)
runnerListResp := MakeRequest(t, req, http.StatusOK)
runnerList := api.ActionRunnersResponse{}
DecodeJSON(t, runnerListResp, &runnerList)

assert.Len(t, runnerList.Entries, 1)
assert.Equal(t, "runner_to_be_deleted-repo1", runnerList.Entries[0].Name)
assert.Equal(t, int64(34348), runnerList.Entries[0].ID)
assert.False(t, runnerList.Entries[0].Ephemeral)
assert.Len(t, runnerList.Entries[0].Labels, 2)
assert.Equal(t, "runner_to_be_deleted", runnerList.Entries[0].Labels[0].Name)
assert.Equal(t, "linux", runnerList.Entries[0].Labels[1].Name)

// Verify get the runner by id
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/user2/repo1/actions/runners/%d", runnerList.Entries[0].ID)).AddTokenAuth(token)
runnerResp := MakeRequest(t, req, http.StatusOK)

runner := api.ActionRunner{}
DecodeJSON(t, runnerResp, &runner)

assert.Equal(t, "runner_to_be_deleted-repo1", runner.Name)
assert.Equal(t, int64(34348), runner.ID)
assert.False(t, runner.Ephemeral)
assert.Len(t, runner.Labels, 2)
assert.Equal(t, "runner_to_be_deleted", runner.Labels[0].Name)
assert.Equal(t, "linux", runner.Labels[1].Name)

// Verify delete the runner by id
req = NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/repos/user2/repo1/actions/runners/%d", runnerList.Entries[0].ID)).AddTokenAuth(token)
MakeRequest(t, req, http.StatusNoContent)

// Verify runner deletion
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/user2/repo1/actions/runners/%d", runnerList.Entries[0].ID)).AddTokenAuth(token)
MakeRequest(t, req, http.StatusNotFound)
}

func TestAPIRunnerDeleteReadScopeForbiddenRepoApi(t *testing.T) {
defer tests.PrepareTestEnv(t)()
userUsername := "user2"
token := getUserToken(t, userUsername, auth_model.AccessTokenScopeReadRepository)

// Verify delete the runner by id is forbidden with read scope
req := NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/repos/user2/repo1/actions/runners/%d", 34348)).AddTokenAuth(token)
MakeRequest(t, req, http.StatusForbidden)
}

func TestAPIRunnerGetRepoApi(t *testing.T) {
defer tests.PrepareTestEnv(t)()
userUsername := "user2"
token := getUserToken(t, userUsername, auth_model.AccessTokenScopeReadRepository)
// Verify get the runner by id with read scope
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/user2/repo1/actions/runners/%d", 34348)).AddTokenAuth(token)
runnerResp := MakeRequest(t, req, http.StatusOK)

runner := api.ActionRunner{}
DecodeJSON(t, runnerResp, &runner)

assert.Equal(t, "runner_to_be_deleted-repo1", runner.Name)
assert.Equal(t, int64(34348), runner.ID)
assert.False(t, runner.Ephemeral)
assert.Len(t, runner.Labels, 2)
assert.Equal(t, "runner_to_be_deleted", runner.Labels[0].Name)
assert.Equal(t, "linux", runner.Labels[1].Name)
}

func TestAPIRunnerGetOrganizationScopeForbiddenRepoApi(t *testing.T) {
defer tests.PrepareTestEnv(t)()
userUsername := "user2"
token := getUserToken(t, userUsername, auth_model.AccessTokenScopeReadOrganization)
// Verify get the runner by id with read scope
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/user2/repo1/actions/runners/%d", 34348)).AddTokenAuth(token)
MakeRequest(t, req, http.StatusForbidden)
}

func TestAPIRunnerGetAdminRunnerNotFoundRepoApi(t *testing.T) {
defer tests.PrepareTestEnv(t)()
userUsername := "user2"
token := getUserToken(t, userUsername, auth_model.AccessTokenScopeReadRepository)
// Verify get a runner by id of different entity is not found
// runner.Editable(ownerID, repoID) false
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/user2/repo1/actions/runners/%d", 34344)).AddTokenAuth(token)
MakeRequest(t, req, http.StatusNotFound)
}

func TestAPIRunnerDeleteAdminRunnerNotFoundRepoApi(t *testing.T) {
defer tests.PrepareTestEnv(t)()
userUsername := "user2"
token := getUserToken(t, userUsername, auth_model.AccessTokenScopeWriteRepository)
// Verify delete a runner by id of different entity is not found
// runner.Editable(ownerID, repoID) false
req := NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/repos/user2/repo1/actions/runners/%d", 34344)).AddTokenAuth(token)
MakeRequest(t, req, http.StatusNotFound)
}

func TestAPIRunnerDeleteNoConflictWhileJobIsDoneRepoApi(t *testing.T) {
defer tests.PrepareTestEnv(t)()
userUsername := "user2"
token := getUserToken(t, userUsername, auth_model.AccessTokenScopeWriteRepository)

_, err := db.GetEngine(t.Context()).Insert(&actions_model.ActionTask{
RunnerID: 34348,
Status: actions_model.StatusSuccess,
})
assert.NoError(t, err)

// Verify delete the runner by id is ok
req := NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/repos/user2/repo1/actions/runners/%d", 34348)).AddTokenAuth(token)
MakeRequest(t, req, http.StatusNoContent)
}