- Remove residual <<<<<<< HEAD marker from api_org_test.go
- Convert code.gitea.io/gitea to mokoconsulting paths in 5 new test files:
cmd/serv_test.go, models/auth/twofactor_test.go,
modules/git/commit_info_nogogit_test.go,
routers/private/hook_pre_receive_test.go,
services/actions/notifier_helper_test.go
- Add changelog entries for new features (#460, #507, #513)
Claude-Session: https://claude.ai/code/session_011AAFzotGMf3ayvXhEmStCd
Backport #38009
The OAuth2 sign-in callback unconditionally set IsActive=true on the
local user row whenever the IdP authenticated them, silently undoing an
administrator's "Disable Account" action and granting the user a fresh
session in the same response. Treat the local IsActive flag as an
authoritative admin override: inactive users get a session and are
routed through the existing activate / prohibit-login pages by
verifyAuthWithOptions, matching the local-credentials sign-in path.
Adds an integration regression test that disables a linked local user
and asserts the row stays IsActive=false after a full OIDC callback.
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #38074Fixes#38062.
Private repositories with a code unit configured for **anonymous read
access** (Settings → Public Access → Code: anonymous view) could not be
cloned without credentials. The git HTTP auth gate (`httpBase`) only
bypassed authentication for non-private repos, ignoring the per-unit
anonymous access setting entirely.
- Check anonymous permissions via
`access_model.GetDoerRepoPermission(ctx, repo, nil)` + `CanAccess`
before requiring auth on pull operations, so the per-unit
`AnonymousAccessMode` is respected through the existing permission model
- This also correctly handles `setting.Repository.ForcePrivate` (which
the naive direct-field check would have missed)
- Push (receive-pack) and `RequireSignInViewStrict` continue to require
credentials as before
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #38103
- Enforce org visibility on organization label read endpoints (private
org labels no longer leak to non-members).
- Block fork sync (`merge-upstream`) when the base repo is no longer
readable (stops pulling commits after a parent goes private).
- Remove `REVERSE_PROXY_LIMIT` / `REVERSE_PROXY_TRUSTED_PROXIES` from
the Docker `app.ini` templates (the `= *` default allowed
`X-WEBAUTH-USER` impersonation; reverse-proxy auth is now opt-in and
admin-configured).
- Enforce single-use TOTP passcodes across web login, password-reset,
and Basic-Auth `X-Gitea-OTP` (fixes a TOCTOU race and a stateless
replay).
- Re-check branch write permission for every ref in a push (the
pre-receive hook cached the first ref's result, letting a per-branch
maintainer-edit grant escalate to full repo write).
---------
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #37875
This fixes an OIDC sign-in edge case where a stale `external_login_user`
record can still point to an organization or a deleted user.
In that situation, Gitea may keep resolving the external login to the
wrong account during sign-in. For affected instances, this matches the
behavior reported in #36439 and #37812, where a user signing in with
OIDC/Entra ID could appear as an organization, or hit a 404 after that
organization was removed.
- validate the user resolved from `external_login_user` during
OAuth2/OIDC login
- ignore stale links when the linked user no longer exists
- ignore stale links when the linked user is not an individual user
- remove the stale external login row so the sign-in flow can relink the
external account to the correct user
- Fixes#37812
- Related to #36439
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.8) <noreply@anthropic.com>
Co-authored-by: bircni <bircni@icloud.com>
Backport #38108
- Enforce repository token scope on RSS/Atom feed endpoints so a PAT
without repo scope can no longer read private repo commit data.
- Block HTTP redirects during repository migration clones to prevent
SSRF reaching internal addresses via an attacker-controlled redirect.
- Redact the notification subject after repo access is revoked so
private issue/PR metadata is no longer leaked through the notification
API.
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Backport #38010 by @bircni
`ifNeedApproval` in `services/actions/notifier_helper.go` decided
whether a
fork PR's workflow run had to wait for maintainer approval. The bypass
clause
counted any prior `approved_by > 0` run for `(repo_id,
trigger_user_id)`, so
the very first Approve-and-run click on a contributor's fork PR
permanently
trusted that user for every future fork PR in the same repository —
including
PRs whose only change is the workflow YAML itself.
Approving a workflow *run* is not the same as merging *code*. This
change
aligns the gate with GitHub Actions' first-time-contributor model: trust
is
granted only after the user has had a pull request merged in the repo.
## Behavior change
- **Before**: one approval = permanent trust for that user in that repo.
- **After**: every fork PR is gated until the contributor has at least
one
merged PR in the repo.
Existing already-approved runs and merged PRs continue to work; only the
trust criterion for *future* fork PRs changes. Maintainers who rely on
the
implicit "approve once" trust will see the approval banner reappear
until
they merge a PR from that contributor.
---------
Signed-off-by: bircni <bircni@icloud.com>
Co-authored-by: bircni <bircni@icloud.com>
Backport #37660 by @jorgeortiz85
## Summary
Fixes#37528
This PR makes the workflow dispatch API reject workflows that do not
declare `workflow_dispatch`. Previously, `POST
/repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches` could
create an `ActionRun` for a workflow that only declared another event
such as `push`.
The service now validates that the target workflow has a
`workflow_dispatch` trigger before inserting the run. The API maps that
validation failure to `422 Unprocessable Entity`, matching existing
validation failures in this handler.
The regression test creates a push-only workflow, dispatches it through
the public API, asserts the `workflow_dispatch` validation message, and
verifies that no run was inserted.
## Testing
- `go test ./services/actions`
- `TAGS="sqlite sqlite_unlock_notify" make
test-integration#TestWorkflowDispatchPublicApiRequiresWorkflowDispatchTrigger`
- `TAGS="sqlite sqlite_unlock_notify" make
test-integration#TestWorkflowDispatchPublicApi`
## Disclosure
Developed with assistance from OpenAI Codex.
Co-authored-by: Jorge Ortiz <jorge.ortiz@gmail.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Full namespace migration: update the Go module path and all import
statements from git.mokoconsulting.tech to code.mokoconsulting.tech.
Also updates all URL references in templates, workflows, configs,
tests, and documentation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rebrand the built-in actions bot user from upstream Gitea naming to
MokoGitea branding:
- Name: gitea-actions → mokogitea-actions
- FullName: Gitea Actions → MokoGitea Actions
- Email: teabot@gitea.io → mokogitea-actions[bot]@mokoconsulting.tech
Add backward-compatible name recognition so all three bot name variants
(mokogitea-actions, gitea-actions, github-actions) with optional [bot]
suffix resolve to the same system user.
Add WhitelistActionsUser, MergeWhitelistActionsUser, and
ForcePushAllowlistActionsUser toggles to branch protection rules,
allowing CI/CD workflows to push to protected branches when explicitly
enabled. Previously the actions bot (virtual user ID -2) could never be
added to whitelist because updateUserWhitelist() only validates real
database users.
Closes#233
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Backport #37588 by @pandareen
## Summary
Fixes
[go-gitea/gitea#37564](https://github.com/go-gitea/gitea/issues/37564):
when an OIDC provider returns a `picture` claim, Gitea is supposed to
download that image as the user's avatar (if `[oauth2_client]
UPDATE_AVATAR = true`). Two latent bugs prevented this from working
consistently:
1. **Default Go User-Agent rejected by some image hosts.**
`oauth2UpdateAvatarIfNeed` used `http.Get`, which sends `User-Agent:
Go-http-client/1.1`. Hosts like `upload.wikimedia.org` reject that UA
with `403`, and every error path silently returned, so the user was left
with an identicon and **no log line** to diagnose the issue.
2. **Link-account *register* path skipped avatar sync.** First-time OIDC
sign-ins where auto-registration is disabled (or required a
username/password retype) go through `LinkAccountPostRegister`, which
created the user but never called `oauth2SignInSync`. So the avatar /
full name / SSH keys from the IdP were dropped on the floor for those
users, even though the existing-account-link path (`oauth2LinkAccount`)
and the auto-register path (`handleOAuth2SignIn`) both already did the
sync.
## Changes
- `routers/web/auth/oauth.go` — `oauth2UpdateAvatarIfNeed` now uses
`http.NewRequest` + `http.DefaultClient.Do`, sets `User-Agent: Gitea
<version>`, and logs every failure path at `Warn` (invalid URL, fetch
error, non-200, body read error, oversize body, upload error). No silent
failures.
- `routers/web/auth/linkaccount.go` — `LinkAccountPostRegister` now
calls `oauth2SignInSync` after a successful user creation, mirroring the
auto-register and link-existing-account flows.
- `tests/integration/oauth_avatar_test.go` — new
`TestOAuth2AvatarFromPicture` integration test with five sub-cases:
- `AutoRegister_FetchesAvatarFromPictureWithGiteaUA` — happy path,
asserts `use_custom_avatar=true`, an avatar hash is set, exactly one
HTTP request was made, and the request carried a `Gitea ` UA. The mock
server enforces the UA prefix to mirror real-world hosts that reject
Go's default UA.
- `AutoRegister_NonOK_DoesNotUpdateAvatar` — server returns 403; user's
avatar must remain unset.
- `AutoRegister_EmptyPicture_NoFetch` — empty `picture` claim must not
trigger any HTTP request.
- `AutoRegister_UpdateAvatarFalse_NoFetch` — `UPDATE_AVATAR=false` must
not trigger any HTTP request.
- `LinkAccountRegister_FetchesAvatarFromPicture` — guards the
`linkaccount.go` fix; without the new `oauth2SignInSync` call this
assertion fails.
## Test plan
- [x] `go test -tags 'sqlite sqlite_unlock_notify' -run
'^TestOAuth2AvatarFromPicture$' ./tests/integration/ -v` — 5/5 sub-tests
pass.
- [x] Manual: log in as a Keycloak user with `picture` claim pointing at
`https://avatars.githubusercontent.com/u/9919?v=4` — Gitea avatar is
replaced with the GitHub picture.
- [x] Manual: same flow with `https://upload.wikimedia.org/...` —
request now succeeds (or returns a clearly logged `Warn` line if
rate-limited with `429`); previously it silently 403'd.
- [x] Manual: `UPDATE_AVATAR=false` — user keeps the identicon, no
outbound request in container logs.
- [ ] Reviewer: please double-check that no other call sites of
`oauth2UpdateAvatarIfNeed` rely on the old `http.Get` behaviour.
## Related
- Upstream issue: go-gitea/gitea#37564
--------------------------------------------
AI Editor was used in this PR
---------
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: pandareen <7270563+pandareen@users.noreply.github.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Rename the Go module path from code.gitea.io/gitea to
git.mokoconsulting.tech/MokoConsulting/MokoGitea across the entire
codebase.
Scope:
- go.mod module declaration
- 2,235 Go source files (import paths)
- Dockerfile WORKDIR and COPY paths
- Swagger API templates
- golangci.yml linter config
External dependencies (code.gitea.io/gitea-vet, code.gitea.io/sdk/gitea,
gitea.com/gitea/act, etc.) are intentionally NOT renamed — they are
separate upstream modules.
Closes#132
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
backport #37118
This PR closes remaining `public-only` token gaps in the API by making
the restriction apply consistently across repository, organization,
activity, notification, and authenticated `/api/v1/user/...` routes.
Previously, `public-only` tokens were still able to:
- receive private results from some list/search/self endpoints,
- access repository data through ID-based lookups,
- and reach several authenticated self routes that should remain
unavailable for public-only access.
This change treats `public-only` as a cross-cutting visibility boundary:
- list/search endpoints now filter private resources consistently,
- repository lookups enforce the same restriction even when addressed
indirectly,
- and self routes that inherently expose or mutate private account state
now reject `public-only` tokens.
---
Generated by a coding agent with Codex 5.2
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Backport #37704
This PR hardens OAuth token exchange validation by binding exchanged
credentials to the client and redirect URI that originally obtained
them.
What it changes:
- reject refresh token exchanges when the refresh token belongs to a
different OAuth application
- reject authorization code exchanges when the `redirect_uri` in the
token request differs from the `redirect_uri` stored with the
authorization code
- add integration coverage for:
- authorization code exchange with a mismatched redirect URI
- refresh token reuse across two different dynamically created OAuth
applications
Why:
OAuth authorization codes and refresh tokens must remain bound to the
client context that originally received them. Without those checks:
- a valid authorization code can be redeemed against a different
registered redirect URI of the same client
- a refresh token can be replayed by a different OAuth client
---------
Co-authored-by: Nicolas <bircni@icloud.com>
Backport #37695 by @lunny
This PR fixes two permission-checking gaps in Git and LFS request
handling.
## What it changes
- keep wiki Git HTTP pushes on the normal write-permission path, even
when proc-receive support is enabled
- revalidate LFS bearer token requests against the current user state
and current repository permissions before allowing access
- add regression coverage for unauthorized wiki HTTP pushes
- add LFS tests for blocked users, revoked repository access, read-only
upload attempts, and valid write access
## Why
- wiki repositories should not inherit the relaxed refs/for handling
used for normal code repositories
- LFS authorization tokens should not remain usable after a user is
disabled or loses repository access
---------
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Merges 356 commits from upstream Gitea v1.26.1 (bugfix release).
Resolved conflicts in templates by keeping our HelpURL changes,
all other conflicts resolved by taking upstream.
Closes#70
Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1. Fix ugly commit form "warning" message
2. Use JSONError for "Update PR Branch" response
3. Remove useless "timeline" class
4. Make timeline review default to "comment" to avoid icon missing
5. Align PR's "command line instructions" UI
6. Simply "Update PR branch" button logic
And then some TODOs are fixed.
---------
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Almost done
`pull_merge_box.tmpl` only has about 80 lines now, and (almost) all
variable accesses are strictly typed.
---------
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Purpose:
1. Make the whole code base have unified "item" layout
2. Clarify our "list" styles: "flex-relaxed-list", "flex-divided-list"
3. Prepare to replace legacy "ui relaxed list"
* https://github.com/go-gitea/gitea/pull/37445#discussion_r3144458865
4. Prepare for refactoring the "pull merge box", it needs the
"flex-divided-list"
* related to "Refactor pull request view (*)" like #37451
5. Fix legacy abuses of "flex-list", e.g.: repo home sidebar
Clean up legacy copied&pasted code, introduce the unique "database
connection" function. Move migration testing helper function
PrepareTestEnv to a separate package.
By the way, remove "shadow connection secrets" tricks: showing
connection string on UI is useless
---------
Co-authored-by: Nicolas <bircni@icloud.com>
## Summary
This PR adds support for updating pull mirror authentication via the
repository edit API and UI.
It introduces new mirror authentication fields in _EditRepoOption_,
updates the API logic to safely handle partial credential updates, and
fixes the web settings flow so that the existing remote username is
preserved when only the password is changed.
### What changed
- added _auth_username_, _auth_password_, and _auth_token_ to
EditRepoOption
- updated the repository edit API to apply mirror auth changes via
_updateMirror_
- preserved existing username/password when only part of the auth
payload is provided
- used oauth2 as the default username when _auth_token_ is provided
- kept stored mirror URLs sanitized in DB and API responses
- updated Swagger schema for the new API fields
- added API integration tests for password-only and token-only updates
- added a web settings test to ensure username preservation on partial
updates
## Why
Some use cases require automated synchronization of pull mirrors, for
example in CI/CD pipelines or integrations with external systems.
At the same time, many organizations enforce security policies that
require periodic token rotation (e.g., monthly).
Currently, mirror credentials can only be updated via the UI, which
makes automation difficult.
## This change enables:
- automated token rotation
- avoiding manual updates via the UI
- easier integration with secret management systems
## Testing
- added integration coverage for mirror auth updates via _PATCH
/api/v1/repos/{owner}/{repo}_
- added web settings tests for password-only updates preserving the
existing username
## Result
Ability to automate auth update
<img width="2400" height="1245" alt="1"
src="https://github.com/user-attachments/assets/67fd5cca-9cb3-4536-b0e2-4d09b8ebff0f"
/>
<img width="962" height="932" alt="image"
src="https://github.com/user-attachments/assets/5d548f5d-aadf-4807-ba52-9c29df93a4cc"
/>
Generative AI was used to help with making this PR.
##
Add a build-time conversion step that transforms the existing Swagger
2.0 spec into an OpenAPI 3.0 spec. The OAS3 spec is served alongside the
existing Swagger 2.0 spec, enabling API clients that require OAS3 to
generate code directly from Gitea's API.
This is not to be an answer to how gitea handles OAS3 long term,
but a way to use what we have to move a step forward.
---------
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Avoid per-item DB queries in ListRuns, ListJobs, and ListActionTasks by
batch-loading trigger users, repositories, and task attributes before
the conversion loop. Remove ReferencesGitRepo from the /actions route
group since no task/run endpoints use it.
Added tests for these endpoints as well.
---------
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>