For repos with many issues, the GitHub API only allows cursor-based
pagination instead of page-based pagination after a certain page.
A full migration of such repos failed with a 422 response.
Now, we dynamically switch how we migrate based on the response from the GitHub API.
Fixes#39882
---------
Signed-off-by: Phoenix <44333391+yuhongwei380@users.noreply.github.com>
Co-authored-by: delvh <dev.lh@web.de>
Co-authored-by: silverwind <me@silverwind.io>
Several `/repos/{owner}/{repo}/issues/{index}/...` API endpoints load
the issue by index without checking
`CanReadIssuesOrPulls(issue.IsPull)`, unlike `GetIssue`,
`ListIssueComments` and `GetIssueReactions`. The route group's
`mustEnableIssuesOrPulls` passes when the caller can read either unit,
so someone who can read issues but not pull requests (a team with only
the Issues unit, or per-unit anonymous access on a public repo) can read
a pull request's whole conversation through `/timeline`, plus its
labels, subscribers, attachments and tracked times, and can subscribe to
it. The reverse holds for issues.
These handlers now return 404 in that case, like their siblings.
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Fixes https://github.com/go-gitea/gitea/issues/39925
RFC 6749 §2.3.1 has clients form-urlencode the client id and secret
before building the HTTP Basic header. `openid-client` with
`client_secret_basic` does this and sends `-` as `%2D` and `_` as `%5F`.
The token and introspection endpoints used the raw header values, so
these clients failed with `invalid_client`. Both endpoints now decode
the values with `url.QueryUnescape` before the client lookup, the secret
check and the body consistency check, and reject a value that does not
decode. Plain HTTP Basic parsing in `httpauth` is unchanged, since the
encoding only applies to OAuth client authentication.
Clients that don't encode are unaffected, since no client id or secret
Gitea has ever issued contains `+` or `%`.
---------
Co-authored-by: silverwind <me@silverwind.io>
Sorting by an exclusive label scope joined `issue_label`, returning one
row per label. Issues with several labels were listed repeatedly and
pushed others off the page, and `IssueIDs` returned inflated totals.
The sort key now comes from a correlated subquery, so each issue yields
one row.
Fixes: https://github.com/go-gitea/gitea/issues/35711
Co-authored-by: silverwind <me@silverwind.io>
When `navigator.clipboard.readText()` runs before the page's copy has
landed, Firefox shows its "Paste" prompt, which cannot be interacted
with when headless. Avoid that and and use
`dom.events.testing.asyncClipboard` which is a pref meant for testing
that disabes this prompt.
Fixes: https://github.com/go-gitea/gitea/actions/runs/39113819632/job/117635434106
Signed-off-by: silverwind <me@silverwind.io>
`go test -count=2` failed in 12 packages because tests leaked state into
later runs.
- Reset SQLite sequences after each fixture load, like PostgreSQL
already does
- Prepare the database in tests that relied on earlier tests doing it
- Restore mutated globals with `test.MockVariableValue`
`PATCH /repos/{owner}/{repo}/milestones/{id}` always overwrote the due
date with `due_on`, so a request that only changed other fields, such as
`{"state": "closed"}`, silently removed it.
The due date is now kept when `due_on` is omitted, and `"due_on": null`
or `"due_on": ""` remove it.
---------
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
`make lint-go` ran `go install` and then a bare `golangci-lint` from
`PATH`, which fails when `GOBIN` is not in `PATH` and overwrites any
`golangci-lint` installed there. It now uses `go run -exec 'env
GOOS=<target>'`, which builds golangci-lint for the host and passes the
lint target `GOOS` only to golangci-lint.
`deps-tools` prebuilds the tools with `go run -exec true` instead of `go
install`, because `go install` does not fill the executable cache that
`go run` uses.
Also drops the unused `TAGS` env and the redundant OS name in
`--build-tags`.
The compare page hid the diff when a comparison had no commits, even if
the trees differ. A direct comparison whose head is an ancestor of its
base hits this, which is where the Compare link on a force-push comment
leads after commits were dropped.
The diff box now shows whenever there are commits or changed files, with
the header reading "0 Commits".
Fixes: https://github.com/go-gitea/gitea/issues/36390
Co-authored-by: silverwind <me@silverwind.io>
Release webhook notifications never mention attached files, although the
payload carries them.
The summary shared by all webhook providers now appends an asset count
like `(assets: 2)` for created and updated releases.
Closes https://github.com/go-gitea/gitea/issues/39630
Co-authored-by: silverwind <me@silverwind.io>
Code comments next to a diff hunk could show one line too high in the
conversation view vs. in the code view that showed them on the correct
line.
- Treat the hunk end in `CutDiffAroundLine` as exclusive, so the line
after a hunk falls back to the unchanged-line context
- Don't count `\ No newline at end of file` markers as lines when
cutting the hunk
- Share the unchanged-line fallback with migrated review comments
The RubyGems compact index (the shared `/versions` file and per-package
`info/<name>` files) is line-based.
https://github.com/go-gitea/gitea/pull/38061 rejected line breaks in the
gem name, but the platform, dependency names and version requirements
from the gemspec still accepted them, letting an uploader forge index
lines for bundler clients.
The parser now rejects a line break in any of those fields. The Marshal
based endpoints are length prefixed and unaffected.
Co-authored-by: silverwind <me@silverwind.io>
Matching git's stderr text is fragile because it breaks silently when
git rewords a message. Where git offers an exit code or a query with a
defined answer, use that instead, and drop matches that could never
trigger. Follow-up to the discussion in https://github.com/go-gitea/gitea/pull/39857.
- Detect a missing remote by `git remote` exit code 2
- Resolve annotated tags to their tree with cat-file `^{tree}` instead
of spawning `ls-tree` when listing tree entries
- Skip the wiki page lookup when the default branch doesn't exist yet
- Remove unreachable "no merge base" and "unknown revision" checks
Hovering a button in a primary or red button group showed a grey frame,
because the generic group hover border applied to colored groups too.
Green groups had no colors at all.
Colored groups now let the hover background fill the border, and green
groups get the same colors as primary and red. The devtest page shows
all three.
<img width="569" height="304" alt="Hovered buttons in uncolored,
primary, red and green button groups, before and after"
src="https://github.com/user-attachments/assets/e0fb6b16-f1f1-459b-9848-9386cd9453c9"
/>
Extracted from https://github.com/go-gitea/gitea/pull/38404
strings.Split("", ",") returns []string{""} (length 1), not an empty
slice, so the previous len(splitted) > 0 guard was always true and never
skipped the label ID lookup, even when the labels query param was
absent. Check the raw trimmed param for emptiness before splitting,
mirroring the pattern already used elsewhere in this file.
Fixes: https://github.com/go-gitea/gitea/issues/39889
Replace Fomantic's hard-forked jQuery modal with native `<dialog>`
elements, advancing https://github.com/go-gitea/gitea/issues/29849. The
UI is visually unchanged. Dialogs open with `show()` over an `inert`
page, so tooltips, popups and toasts mounted on `<body>` stay usable
above them, unlike with `showModal()`
(https://github.com/whatwg/html/issues/9936).
- Remove the Fomantic modal and dimmer, add `showModal` and `hideModal`
- Declare modals as `<dialog class="modal-dialog">`, shown inside a
`.modal-backdrop`, instead of `ui modal` with its unused size classes
- Remove two modals that could never be opened
- Block the page while a modal is open, close the topmost one on Escape
and restore focus to its opener
- Allow stacked modals, use a confirm modal instead of `window.confirm`
for deleting content history
- Hide popups and toasts when a modal opens or closes
- Keep the release notes modal open when generating notes fails
Fixes: https://github.com/go-gitea/gitea/issues/39643
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Adds a repository setting for the default squash merge commit message
body with GitHub's options `PR_BODY`, `COMMIT_MESSAGES` and `BLANK`,
also settable via `squash_merge_commit_message` in the API. The commit
title stays the pull request title.
1. Breaking: API squash merges without `merge_message_field` now get the
same default message as the web merge box instead of a title-only
commit, which affects clients sending only `Do` like Renovate. An empty
value keeps title-only.
2. Breaking: `[repository.pull-request] DEFAULT_SQUASH_MERGE_MESSAGE`
replaces `POPULATE_SQUASH_COMMENT_WITH_COMMIT_MESSAGES`, which still
works as a deprecated fallback. Repositories store the default when
created or next saved.
3. Deprecated app.ini keys now migrate through one table instead of
per-loader fallbacks, which also fixes the ignored `[mailer] CERT_FILE`
and `KEY_FILE` fallbacks. Deprecation warnings no longer claim a removal
version.
<img width="1891" height="571" alt="grafik"
src="https://github.com/user-attachments/assets/0fdcde13-1f11-4156-b598-d80eb0d04cbe"
/>
---------
Co-authored-by: silverwind <me@silverwind.io>
The token a request authenticated with now lives on the doer, so
permission and visibility checks apply its scope from the doer alone.
Replaces https://github.com/go-gitea/gitea/pull/39167, following
https://github.com/go-gitea/gitea/pull/39167#issuecomment-6063839619.
1. Public-only tokens get 404 instead of 403 for hidden users, orgs and
repos, like GitHub.
2. Org ownership, site admin, repo and org creation, generation and
transfer endpoints reject public-only tokens.
3. API pull request responses set `head.repo` to `null` and
`head.repo_id` to `-1` when the caller cannot see the head repository.
4. Public-only tokens see org memberships like anonymous callers, so
concealed members stay hidden.
5. Site admin access in activity feeds, follower lists, org members,
Actions run lists and packages needs a session or an `all`-scoped token.
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Move the remaining legacy init code, which probed page classes with
`querySelector`, to `data-global-init`, so each feature initializes from
its own element. `hashchange` listeners now go through one module that
runs them in priority order, because independent listeners broke when
mount order changed.
- Convert issue list, diff, repo create, settings and org team inits to
`data-global-init`
- Run `hashchange` listeners by priority, the diff scroll handler last
- Make the devtest mock's failing log requests deterministic
- Add e2e tests for diff tree navigation to folded files and job log
permalinks
---------
Co-authored-by: silverwind <me@silverwind.io>
Several handlers and model helpers skipped checks that their siblings
already perform.
- Only match principal keys when looking up SSH certificate principals
- Return no attachments for an unsaved issue instead of every issue-less
one
- Reject issue and comment attachments when adding release attachments
- Share one permission check for editing, deleting and reacting to issue
content and for comment attachments between the web UI and the API,
refusing them on locked issues for users who can't write
- Reject issue edits, deletion and label changes in archived
repositories via the API
- Apply cross-origin protection to the repository topics endpoint
- Return 404 for the repositories tab of individual users and respect
profile visibility for the heatmap
Fixes: https://github.com/go-gitea/gitea/issues/39226
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: bircni <bircni@icloud.com>
Integration test processes now get their own work directory, config file
and random ports, so several runs can execute in parallel on one
machine. The slowest tests also lose fixed sleeps and needlessly
expensive setup, with their assertions kept.
- Batch PostgreSQL sequence resets, the main per-test fixture cost there
- Cheap hashing params in hash and OAuth2 fixture tests, full-cost
vectors stay
- Single fetch for negative Actions runner assertions instead of 1s
polls
- Queue flushes and backdated timestamps instead of sleeps
- In-memory SQLite test journal, tmpfs for PostgreSQL in CI
- E2E instance writes SSH keys into its work directory instead of
`~/.ssh/authorized_keys`
`TreeCommon` only holds `ID` and is embedded solely by `Tree`, with no
other users. Inline the field into `Tree`; `t.ID` access is unchanged.
Assisted-by: Codet:codet
Incoming email reply tokens are embedded in every notification email and
stay valid for a year. `DecodeToken` verifies them with `user.Rands`,
which is not rotated when an admin disables sign-in or the account is
deactivated, and `ReplyHandler` only checks repo read permission. A
suspended user could therefore keep posting comments, review comments
and attachments on any public repo by replying to old notifications,
while the web, API, git and package paths all refuse them. `DecodeToken`
now rejects tokens of users who are inactive or prohibited from signing
in, which covers every incoming mail handler.
---------
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
When pushing the merge commit to the base repo fails (e.g.
non-fast-forward), the merge intent recorded by
https://github.com/go-gitea/gitea/pull/39442 is left behind.
`merged_commit_id` then points to a commit that does not exist in the
base repo, and `git branch --contains` fails with `no such commit`, so
the PR can never be checked or merged again.
- Clear the recorded merge intent if the push fails and the commit is
not on the base branch
- `IsCommitInBranch` now returns false for a missing commit, so
already-stuck PRs recover on the next check
Fixes https://github.com/go-gitea/gitea/issues/39824
_Written with Codet assistance._
---------
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Giteabot <teabot@gitea.io>
Users with "Only Email on Mention" can now still receive email for the
events they picked in a custom repository watch, covering issues, pull
requests and releases. The setting is renamed to "Only Email on Mention
and Custom Watches" to make this explicit, matching GitHub's
"Participating, @mentions and custom".
"All activity" watches don't bypass the setting, because they are also
created automatically by `AUTO_WATCH_NEW_REPOS` for repository creators
and team members. To keep picking every event distinct from "All
activity", the custom watch dialog now stores a new `WatchModeCustom`.
Existing custom watches keep working without a migration.
## Screenshots
### Before
<img width="1650" height="675" alt="grafik"
src="https://github.com/user-attachments/assets/ecc56e20-cd05-41e9-a840-607b352c50a8"
/>
### After
<img width="1657" height="671" alt="grafik"
src="https://github.com/user-attachments/assets/a406db94-3ac4-4587-b840-0cd472b135c5"
/>
Addresses https://github.com/openSUSE/openSUSE-git/issues/183
Ref: https://github.com/go-gitea/gitea/issues/35492
---------
Co-authored-by: bircni <bircni@icloud.com>
Co-authored-by: Giteabot <teabot@gitea.io>
In Firefox and in Chromium on Linux, the `math` font family resolves to
Latin Modern Math when it is installed. Its hairline strokes are too
thin for screens, so MathML looks noticeably weaker than KaTeX on the
same page.
List sturdier math fonts before `math`: Cambria Math, STIX Two Math, New
Computer Modern Math Book (aliased via `local()` because it shares its
family name with the thinner Regular), Libertinus Math and DejaVu Math
TeX Gyre. `math` stays as the fallback before Noto Sans Math. No fonts
are shipped, so systems with only Latin Modern Math, or no math font at
all, are unchanged.
Fixes: https://github.com/go-gitea/gitea/issues/39665
Co-authored-by: silverwind <me@silverwind.io>
getPullRequestInfo and getIssuesInfo indexed into the last element of an
empty Assignees slice when Action was HookIssueAssigned, causing a panic
under a race where the assignee list is empty by the time the webhook
payload is built.
Fixes https://github.com/go-gitea/gitea/issues/39826
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Remove the misspell spell checker along with its `lint-spell` and
`lint-spell-fix` make targets, its CI step and its custom dictionary.
`make lint` and `make lint-fix` no longer run a spell check.
Co-authored-by: Giteabot <teabot@gitea.io>
https://github.com/go-gitea/gitea/pull/38046 accidentally dropped
`gitea/unescaped-html-literal` from the eslint config, so it has been
off since. Raised in
https://github.com/go-gitea/gitea/pull/39829#issuecomment-6246720235.
- Re-enable the rule, exempting e2e tests like unit tests
- Detect tags anywhere in strings and template chunks, not only at the
start
- Allow `htmlRaw` templates, they escape like `html`
- Fix the existing violations, which escapes the heatmap tooltip and
shortcut keys
Adds OpenID Connect workload identity to Gitea Actions: jobs declaring
`id-token: write` can request short-lived tokens to authenticate to
cloud providers and other services without stored secrets. Tokens follow
GitHub's format, so clients like `@actions/core` and existing trust
policies carry over.
- Issuer at `/api/actions/oidc` with discovery and JWKS, signed with a
dedicated RS256 key
- GitHub's claims, including `workflow_ref`, `job_workflow_ref` and the
immutable `repo:owner@id/repo@id:ref:...` subject
- `id-token: write` or `write-all` grant it, default permissions and
fork pull requests never get it, owner and repository maximum
permissions can disable it
- Reusable workflows record the exact ref they were loaded from, and
dispatch rejects refs that only resolve through a same-named tag
- Generated signing keys are written atomically, and generated ES384 and
ES512 OAuth2 keys use their own curves instead of P-256
- `github.ref_type` is `branch` for pull request runs, like on GitHub
Fixes https://github.com/go-gitea/gitea/issues/26383
Fixes https://github.com/go-gitea/gitea/issues/33681
Docs: https://gitea.com/gitea/docs/pulls/526
Assisted-by: ChatGPT:gpt-5.6-sol, Claude Code:claude-opus-5-5
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>