## Summary
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.
## What changed
- 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
## Related
- Fixes#37812
- Related to #36439
---------
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.8) <noreply@anthropic.com>
This PR hardens artifact URL signing by encoding signature inputs in an
unambiguous binary payload before computing the HMAC.
What it changes:
- replace direct concatenation-style signing inputs with explicit
payload builders
- encode string fields with a length prefix before appending their bytes
- encode integer fields as fixed-width binary values instead of decimal
text
- apply the same hardening to both:
- Actions Artifact V4 signing in `routers/api/actions/artifactsv4.go`
- artifact download signing in `routers/api/v1/repo/action.go`
- add regression tests that verify distinct field combinations produce
distinct payloads and signatures
Why:
The previous signing logic built HMAC inputs by appending multiple
fields without a strongly structured representation. That kind of
construction can create ambiguity at field boundaries, where different
parameter combinations may serialize into the same byte stream for
signing.
This change removes that ambiguity by constructing a deterministic
payload format with explicit boundaries between fields.
---------
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
## What
This PR updates the giteabot workflows to use the newer action version
that supports selecting individual checks, and splits the workflow into
two separate jobs:
- `giteabot backport` runs only the `backport` check on pushes to `main`
- `giteabot` handles the remaining bot tasks on PR-related events,
scheduled runs, and manual dispatch
## Why
Previously, the single workflow handled both backporting and the other
maintenance tasks together.
With the new giteabot action supporting configurable checks, splitting
the workflow makes the triggers clearer and avoids running non-backport
maintenance on every push to `main`.
## Changes
- upgrade `go-gitea/giteabot` to a revision that supports the `checks`
input
- move the `main` branch `push` trigger into a dedicated backport
workflow
- keep non-backport automation in the existing workflow
- add a `workflow_dispatch` input so non-backport checks can be selected
manually when needed
---
Helped by a coding agent with Codex 5.4
---------
Co-authored-by: Nicolas <bircni@icloud.com>
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>
This PR tightens several OAuth validation paths related to PKCE
handling, redirect URI normalization, and refresh-token replay safety.
What it changes:
- switch redirect URI comparison to ASCII-only normalization for
exact-match checks, avoiding Unicode case-folding surprises
- harden PKCE verification by:
- allowing PKCE omission only when no challenge data was stored
- rejecting exchanges with a missing verifier when PKCE was used
- rejecting malformed challenge state where a challenge exists without a
valid method
- comparing derived challenges with constant-time string matching
- make refresh-token invalidation counter updates conditional on the
previously observed counter value, so stale refresh state cannot be
accepted after the grant changes
Why:
These checks close gaps where:
- redirect URI comparisons could rely on broader Unicode normalization
than intended
- malformed or incomplete PKCE state could be treated too permissively
- concurrent or stale refresh-token use could advance the same grant
more than once
---------
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
This PR tightens token-scope enforcement for non-API download endpoints
in the web layer.
What it changes:
- require `read:repository` for repository content downloads served from
web routes such as:
- `/raw/...`
- `/media/...`
- enforce attachment-specific scopes in `ServeAttachment`:
- issue / pull request attachments require `read:issue`
- release attachments require `read:repository`
- centralize token-scope checks for web handlers with a shared context
helper
- add matrix-style integration coverage for:
- public and private repository content downloads
- `blob`, `branch`, `tag`, and `commit` download routes
- global and repo-scoped attachment routes
- `public-only` token behavior on public vs private resources
Why:
API tokens and OAuth access tokens can be used on some non-API web
endpoints. Before this change, those endpoints relied on repository
visibility and unit permissions, but did not consistently enforce the
token’s declared scope. That allowed scoped tokens to access resources
beyond their intended category through web download routes.
---------
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
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: wxiaoguang <wxiaoguang@gmail.com>
1. make "pull" and "build" testable and debuggable
2. add more comments for how the build works
3. separate 1.26 and main build tags
4. fix incorrect tag describe (the current `snap info gitea` outputs
version 1.22)
Legacy logic is kept as is although some of them don't seem good (e.g.:
snap version grep, tag finding, etc)
---------
Signed-off-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
A quick fix#37317
---
The current behavior for forks when an organization or repository is
changed to private differs from GitHub.
On GitHub, when a parent repository becomes private, the fork
relationship is removed, which keeps the behavior simple and avoids
visibility conflicts.
I think we need a similar solution to handle cases where the parent
repository becomes private while a fork remains public and the fork
relationship is still preserved.
---------
Signed-off-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
When generating release notes for v1.26, many pull requests haven't been
given correct labels so that I have to do many manual work. I think this
could be avoid to remove these useless modify labels.
Fix#36905
The changes focus on force-push PR timeline handling and commit range
calculation:
- Reworked pull-request push comment creation to use a new
`gitrepo.GetCommitIDsBetweenReverse` helper, with special handling for
force pushes (merge-base based range, tolerate missing/invalid old
commits, and keep force-push timeline entries).
- Added `Comment.GetPushActionContent` to parse push comment payloads
and used it to delete only non-force-push push comments during force
pushes.
- Removed the old `Repository.CommitsBetweenNotBase` helper from
`modules/git/repo_commit.go` in favor of the new commit ID range helper.
- Added tests for `GetCommitIDsBetweenReverse` (normal range, `notRef`
filtering, fallback branch usage) and expanded pull comment tests to
cover force-push edge cases.
<img width="989" height="563" alt="image"
src="https://github.com/user-attachments/assets/a01e1bc2-fa8a-4028-8a35-d484e601ff3b"
/>
---------
Signed-off-by: Lunny Xiao <xiaolunwen@gmail.com>
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
- set OAuth2 authorization code `ValidUntil` on creation and add expiry
checks during exchange
- return a specific error when codes are invalidated twice to prevent
concurrent reuse
- add unit tests covering validity timestamps, expiration, and double
invalidation
---
Generate by a coding agent with Codex 5.2
---------
Signed-off-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
- fix wrong parameter of HasOrgOrUserVisible in
routers/api/v1/org/org.go
- add integration tests covering the bug fix
- merge permissions API tests
---
Generated by a coding agent with Codex 5.2
When checking whether a user can update a pull request branch or perform
an update via rebase, a maintainer should inherit the pull request
author’s permissions if Allow maintainer edits is enabled.
---------
Signed-off-by: Lunny Xiao <xiaolunwen@gmail.com>
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This PR hardens the handling of the “open-link” action in render iframes
(external rendering iframes). It prevents iframes from triggering unsafe
or unintended redirects or opening new windows via postMessage.
Additionally, it improves iframe height reporting to reduce scrollbar
and height mismatch issues, and adds unit test coverage.
---------
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Adds validation constraints to repository creation inputs, enforcing
max-length limits for labels/license/readme and enum validation for
trust model and object format. Updates both the API option struct and
the web form struct to keep validation consistent.
The jobparser sub package in act is only used by Gitea. Move it to Gitea
to make it more easier to maintain.
---------
Co-authored-by: Christopher Homberger <christopher.homberger@web.de>
When display or search branch's pushed time, we should use
`updated_unix` rather than `commit_time`.
Fix#36633
---------
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: silverwind <me@silverwind.io>
Starting with v1.26, Gitea uses a JSON configuration file format instead
of the INI format used in v1.25 and earlier versions.
Because of this fundamental format change, a clean translation backport
to the v1.25 branch (or earlier release branches) is not feasible.The
recommended approach is:
- Wait until the release/v1.26 branch is created after the official
v1.26 release.
- Then introduce a new JSON-based configuration (or
migration/compatibility layer) on top of that branch.
Fix#36448
Removed unnecessary parameters from the LFS GC process and switched to
an ORDER BY id ASC strategy with a last-ID cursor to avoid missing or
duplicating meta object IDs.
---------
Signed-off-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Fix#28479
When scrolling inside the editor and the editor has already reached the
end of its scroll area, the browser does not continue scrolling. This is
inconvenient because users must move the cursor out of the editor to
scroll the page further.
This PR enables automatic switching between the editor’s scroll and the
browser’s scroll, allowing seamless continuous scrolling.
Fix#36483
In git log/rev-list, the "..." syntax represents the symmetric
difference between two references, which is different from the meaning
of "..." in git diff (where it implies diffing from the merge base).
For listing PR commits, we must use `merge-base..head` to include only
the commits introduced by the head branch. Otherwise, commits newly
pushed to the base branch would also be included, which is incorrect.
In Git 2.38, the `merge-tree` command introduced the `--write-tree`
option, which works directly on bare repositories. In Git 2.40, a new parameter `--merge-base` introduced so we require Git 2.40 to use the merge tree feature.
This option produces the merged tree object ID, allowing us to perform
diffs between commits without creating a temporary repository. By
avoiding the overhead of setting up and tearing down temporary repos,
this approach delivers a notable performance improvement.
It also fixes a possible situation that conflict files might be empty
but it's a conflict status according to
https://git-scm.com/docs/git-merge-tree#_mistakes_to_avoid
Replace #35542
---------
Signed-off-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Maybe fix#32018
- Use `gitrepo.GetMergeBase` method instead of other two
implementations.
- Add `FetchRemoteCommit` so that we don't need to add many `remote` to
the git repository to avoid possible git lock conflicts. A lock will
start when invoke the function, it will be invoked when cross-repository
comparing. The head repository will fetch the base repository's base
commit id. In most situations, it should lock the fork repositories so
that it should not become a bottleneck.
- Improve `GetCompareInfo` to remove unnecessarily adding remote.
- Remove unnecessary parameters of `SignMerge`.
When a user has been revoked permission to access a repository, the
related notification could still be visited. But the repository's
information should not be leaked any more.
- The compare page head title should be `compare` but not `new pull
request`.
- Use `UnstableGuessRefByShortName` instead of duplicated functions
calls.
- Direct-compare, tags, commits compare will not display `New Pull
Request` button any more.
The new screenshot
<img width="1459" height="391" alt="image"
src="https://github.com/user-attachments/assets/64e9b070-9c0b-41d1-b4b8-233b96270e1b"
/>
---------
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
- Use `gitrepo.IsRepositoryExist` instead of `util.IsExit` or
`util.IsDir`
- Use `gitrepo.OpenRepository` instead of `git.OpenRepository`
- Use `gitrepo.DeleteRepository` instead of `util.RemoveAll`
- Use `gitrepo.RenameRepository` instead of `util.Rename`
Crowdin does not remove empty lines in nested JSON translation files.
Therefore, we use flattened translation keys instead. We have also
updated the key-loading logic to ensure that empty values are not
applied during translation.
---------
Signed-off-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: TheFox0x7 <thefox0x7@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>