Skip to content

Fix registration token API#36793

Closed
lunny wants to merge 2 commits intogo-gitea:mainfrom
lunny:lunny/fix_registor_token
Closed

Fix registration token API#36793
lunny wants to merge 2 commits intogo-gitea:mainfrom
lunny:lunny/fix_registor_token

Conversation

@lunny
Copy link
Copy Markdown
Member

@lunny lunny commented Mar 1, 2026

Another possible resolution is to remove GET method.

@GiteaBot GiteaBot added the lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. label Mar 1, 2026
@github-actions github-actions bot added modifies/api This PR adds API routes or modifies them modifies/go Pull requests that update Go code labels Mar 1, 2026
Copy link
Copy Markdown
Contributor

@Zettat123 Zettat123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall LGTM. However, I would prefer to remove the GET method because:

  • it's not a real GET method
  • GH doesn't support GET and only POST is allowed

@GiteaBot GiteaBot added lgtm/need 1 This PR needs approval from one additional maintainer to be merged. and removed lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. labels Mar 1, 2026
@lunny lunny added type/bug backport/v1.25 This PR should be backported to Gitea 1.25 labels Mar 2, 2026
@silverwind silverwind requested a review from Copilot March 2, 2026 06:42
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR tightens authorization for Actions runner registration token API endpoints, ensuring that retrieving a registration token via GET requires write token scopes (since the operation can mint/refresh tokens).

Changes:

  • Refactors token-scope middleware to share logic via checkTokenScopes and introduces tokenRequiresScopesLevel(...).
  • Updates runner registration-token GET routes (admin/user/org/repo contexts) to require write scope categories.
  • Extends integration tests to assert GET .../registration-token is forbidden when using read-only scoped tokens.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
tests/integration/api_actions_runner_test.go Adds integration coverage that read-scoped tokens are rejected for GET .../registration-token endpoints.
routers/api/v1/api.go Introduces tokenRequiresScopesLevel and applies it to GET .../registration-token routes to require write scopes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

m *web.Router,
reqChecker func(ctx *context.APIContext),
act actions.API,
requiredScopeCategories ...auth_model.AccessTokenScopeCategory,
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addActionsRoutes now takes requiredScopeCategories as a variadic argument, but checkTokenScopes becomes a no-op when the slice is empty. That makes it easy for a future call site to omit the category and accidentally reintroduce the original scope-bypass on GET .../registration-token. Consider making this a required (non-variadic) parameter for addActionsRoutes, or defensively failing fast when it’s empty for endpoints that must enforce scopes.

Suggested change
requiredScopeCategories ...auth_model.AccessTokenScopeCategory,
requiredScopeCategories []auth_model.AccessTokenScopeCategory,

Copilot uses AI. Check for mistakes.
Comment on lines +929 to 931
m.Get("/registration-token", reqToken(), reqChecker, tokenRequiresScopesLevel(auth_model.Write, requiredScopeCategories...), act.GetRegistrationToken)
m.Post("/registration-token", reqToken(), reqChecker, act.CreateRegistrationToken)
m.Get("/{runner_id}", reqToken(), reqChecker, act.GetRunner)
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description mentions removing the GET method as a resolution, but the route is still present (now with stricter scope enforcement). If the intended fix is to eliminate GET entirely, this should be removed/disabled (and related swagger/docs/tests updated) rather than kept.

Copilot uses AI. Check for mistakes.
m.Group("/runners", func() {
m.Get("", reqToken(), reqChecker, act.ListRunners)
m.Get("/registration-token", reqToken(), reqChecker, act.GetRegistrationToken)
m.Get("/registration-token", reqToken(), reqChecker, tokenRequiresScopesLevel(auth_model.Write, requiredScopeCategories...), act.GetRegistrationToken)
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GET .../registration-token still maps to shared.GetRegistrationToken, which can create a new runner token when none exists or the latest is inactive. Even with the write-scope requirement, using GET for a potentially state-changing operation is problematic (cache/prefetch/logging semantics) and differs from GitHub’s POST-only behavior. Consider making GET strictly read-only (never creating) or returning 405 and requiring POST to create tokens.

Suggested change
m.Get("/registration-token", reqToken(), reqChecker, tokenRequiresScopesLevel(auth_model.Write, requiredScopeCategories...), act.GetRegistrationToken)
m.Get("/registration-token", reqToken(), reqChecker, tokenRequiresScopesLevel(auth_model.Write, requiredScopeCategories...), func(ctx *context.APIContext) {
// For security and HTTP semantics reasons, registration token creation
// must use POST. GET is not allowed to perform this state-changing action.
ctx.Status(http.StatusMethodNotAllowed)
})

Copilot uses AI. Check for mistakes.
Comment on lines +30 to +33
readToken := getUserToken(t, adminUsername, auth_model.AccessTokenScopeReadAdmin)
readReq := NewRequest(t, "GET", "/api/v1/admin/runners/registration-token").AddTokenAuth(readToken)
MakeRequest(t, readReq, http.StatusForbidden)

Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new assertions cover that read-scoped tokens are forbidden for the GET registration-token endpoint, but there’s no corresponding positive test that a write-scoped token can still successfully GET a registration token. Adding a success-path assertion here (or in one of the other contexts) would help catch route/middleware ordering mistakes that could inadvertently block the endpoint entirely.

Copilot uses AI. Check for mistakes.
@lunny lunny marked this pull request as draft March 2, 2026 07:22
@lunny lunny closed this Mar 2, 2026
@lunny lunny deleted the lunny/fix_registor_token branch March 2, 2026 17:44
lunny added a commit that referenced this pull request Mar 2, 2026
Replace #36793

---------

Co-authored-by: ChristopherHX <christopher.homberger@web.de>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport/v1.25 This PR should be backported to Gitea 1.25 lgtm/need 1 This PR needs approval from one additional maintainer to be merged. modifies/api This PR adds API routes or modifies them modifies/go Pull requests that update Go code type/bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants