gitforge/tests/integration/api_private_actions_test.go
Andreas Ahlenstorf 85d38e354d fix: ensure runners either belong to owner or repo when updated (#13262)
A runner can either belong to an owner (user, organization) or a repository, not both. While `CreateRunner()` enforces that, `UpdateRunner()` does not, which leads to bugs. With this change, `UpdateRunner()` rejects runners that have _both_ fields set to prevent unexpected ownership changes.

Resolves https://codeberg.org/forgejo/forgejo/issues/12106 and makes https://codeberg.org/forgejo/forgejo/pulls/12117 obsolete.

### Tests for Go changes

- I added test coverage for Go changes...
  - [x] in their respective `*_test.go` for unit tests.
  - [x] in the `tests/integration` directory if it involves interactions with a live Forgejo server.
- I ran...
  - [x] `make pr-go` before pushing

### Documentation

- [ ] I created a pull request [to the documentation](https://codeberg.org/forgejo/docs) to explain to Forgejo users how to use this change.
- [x] I did not document these changes and I do not expect someone else to do it.

### Release notes

- [x] This change will be noticed by a Forgejo user or admin (feature, bug fix, performance, etc.). I suggest to include a release note for this change.
- [ ] This change is not visible to a Forgejo user or admin (refactor, dependency upgrade, etc.). I think there is no need to add a release note for this change.

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/13262
Reviewed-by: Mathieu Fenniak <mfenniak@noreply.codeberg.org>
2026-07-01 03:49:07 +02:00

93 lines
2.3 KiB
Go

// Copyright 2026 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: GPL-3.0-or-later
package integration
import (
"net/url"
"testing"
"forgejo.org/models/actions"
"forgejo.org/models/unittest"
"forgejo.org/modules/optional"
"forgejo.org/modules/private"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestGenerateActionsRunnerToken(t *testing.T) {
testCases := []struct {
name string
scope string
expectedOwner optional.Option[int64]
expectedRepo optional.Option[int64]
expectedError string
}{
{
name: "instance scope",
scope: "",
expectedOwner: optional.None[int64](),
expectedRepo: optional.None[int64](),
},
{
name: "user scope",
scope: "user2",
expectedOwner: optional.Some[int64](2),
expectedRepo: optional.None[int64](),
},
{
name: "organization scope",
scope: "org3",
expectedOwner: optional.Some[int64](3),
expectedRepo: optional.None[int64](),
},
{
name: "unknown user",
scope: "does-not-exist",
expectedError: "user does not exist",
},
{
name: "repository scope",
scope: "user2/test_workflows",
expectedOwner: optional.None[int64](),
expectedRepo: optional.Some[int64](62),
},
{
name: "empty repository",
scope: "user2/",
expectedError: "repository does not exist",
},
{
name: "unknown repository",
scope: "user2/does-not-exist",
expectedError: "repository does not exist",
},
{
name: "owner mismatch",
scope: "org3/test_workflows",
expectedError: "repository does not exist",
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
onApplicationRun(t, func(*testing.T, *url.URL) {
text, extra := private.GenerateActionsRunnerToken(t.Context(), testCase.scope)
if testCase.expectedError == "" {
require.NoError(t, extra.Error)
newToken := unittest.AssertExistsAndLoadBean(t,
&actions.ActionRunnerToken{OwnerID: testCase.expectedOwner, RepoID: testCase.expectedRepo})
assert.Equal(t, newToken.Token, text.Text)
} else {
assert.ErrorContains(t, extra.Error, testCase.expectedError)
}
})
})
}
}