feat: scope list_repositories to the authenticated user in service-PAT mode
docker / test (push) Successful in 28s
docker / lint (push) Successful in 33s
test / test (push) Successful in 33s
lint / lint (push) Successful in 35s
docker / docker-test (push) Successful in 10s
docker / docker-publish (push) Successful in 6s

Previously list_repositories was blocked in service-PAT mode because it has no
repository target for the per-user permission check, so users could not list
their repositories at all (the connector surfaced a generic error).

list_repositories now returns only the repositories the signed-in user owns or
contributes to, instead of everything the bot token can see:
- gitea_client.py: add list_user_repositories(login) — resolves the user id and
  queries /api/v1/repos/search with the uid filter.
- repository.py: list_repositories_tool uses the user-scoped path when a service
  PAT is configured and a user login is present; pure-OAuth mode still uses the
  user's own /user/repos.
- server.py: allow list_repositories through the service-PAT guard (it is scoped
  to the user in the handler); all other tools still require a repository target.
- README.md: document the new user-scoped behavior and its visibility caveat.

Tests: user-scoped client method (uid resolution + unknown user), PAT-mode tool
scoping, and conftest now clears the request context between tests to prevent
contextvar login leakage across files.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
LatteandClaude Opus 4.8 committed 2026-06-14 17:07:19 +02:00
1 parent 624a3c79ee
commit e873d0325b
7 files changed
+146 -20

No files matched your search

+24 -18
View File
@@ -1165,26 +1165,32 @@ async def _execute_tool_call(
if settings.gitea_token.strip():
if not repository:
audit.log_access_denied(
tool_name=tool_name,
reason="service_pat_requires_repository_target",
# list_repositories is not repo-scoped; the handler scopes it to
# the authenticated user's own repositories instead. Every other
# tool requires a repository target so per-user permission can be
# verified before the privileged service PAT is used.
if tool_name != "list_repositories":
audit.log_access_denied(
tool_name=tool_name,
reason="service_pat_requires_repository_target",
correlation_id=correlation_id,
)
raise HTTPException(
status_code=403,
detail=(
"Service PAT mode requires a repository target so per-user "
"permission can be verified."
),
)
else:
user_login = get_gitea_user_login()
await _verify_user_repository_access(
repository=repository,
required_scope=required_scope,
user_login=user_login or "",
correlation_id=correlation_id,
tool_name=tool_name,
)
raise HTTPException(
status_code=403,
detail=(
"Service PAT mode requires a repository target so per-user "
"permission can be verified."
),
)
user_login = get_gitea_user_login()
await _verify_user_repository_access(
repository=repository,
required_scope=required_scope,
user_login=user_login or "",
correlation_id=correlation_id,
tool_name=tool_name,
)
# In OAuth mode, Gitea OIDC access_tokens can't call the Gitea REST API
# (they only carry OIDC scopes). If a service PAT is configured via