Commit Graph
21845 Commits
Author SHA1 Message Date
Basavaraj S m 269b116b1b fix(feed): hide release notes in tags feed without releases access (#39944)
The tags feed (`tags.rss` / `tags.atom`) lives in the tags route group,
which only requires code read access, yet it lists every published
release next to the plain tags and includes each release's title and
rendered note. The releases page and `releases.rss` require releases
read access, and the tags page only shows tag names to users without it,
so the feed is the one place that leaks. A team member granted Code but
not Releases on a private repo, or anyone on a public repo whose
Releases unit is disabled, can read all release notes this way. I
noticed it while comparing the feed routes with the tags template. When
the doer cannot read releases, the feed now lists releases as plain
tags, linking to `/src/tag/` like the tags page does.
2026-10-22 20:25:44 +00:00
Chris Eastwoodandsilverwind 4bbe1b918a build(tools): install playwright deps only when that needs no prompt (#39905)
On Debian/Ubuntu outside GitHub Actions, `tools/playwright.sh` always
ran `pnpm exec playwright install --with-deps`. Installing system
packages needs root: when it isn't root, Playwright tries `sudo` and
falls back to `su`, so a non-root user without passwordless sudo sees
`make playwright` — and the targets depending on it, `make test-e2e` and
`make test-frontend` — either stop and ask for the root password
mid-build or fail outright with `su: System error`.

Related: #38860, which added this script.
---------

Co-authored-by: silverwind <me@silverwind.io>
2026-10-22 19:59:11 +00:00
bircni 3a70b85220 fix(actions): bound requested artifact retention (#39894) 2026-10-22 19:52:35 +00:00
bircniandsilverwind c11302233b docs: clarify reverse proxy authentication requirements (#39940)
Document that reverse proxy authentication requires Gitea to be
reachable only through the authenticating proxy, and which routes each
setting covers.

Docs: https://gitea.com/gitea/docs/pulls/604
Co-authored-by: silverwind <me@silverwind.io>
2026-10-22 19:35:34 +00:00
silverwind 04c65f26f1 enhance: remove box-shadow from kbd elements (#39943)
Remove the inset bottom shadow from `<kbd>` elements in markup and on
keyboard shortcut hints. The skeuomorphic key cap look is not needed,
the border alone marks the element as a key.
2026-10-22 21:33:50 +02:00
silverwind facc0f2b15 refactor: prevent out-of-bounds read (#39936)
`IsReadmeFileExtension("readme", exts...)` panicked with `index out of
range [6] with length 6` when `exts` had no empty extension. The only
caller always passes one, so this was not reachable in practice.

Fixes:
https://github.com/go-gitea/gitea/security/quality/rules/go%2Findex-out-of-bounds

Written by Claude.
2026-10-22 13:06:01 +00:00
5f8f625ff7 fix(migrations): use cursor pagination for GitHub issue migration too (#39888)
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>
2026-10-22 12:00:12 +00:00
Aradhya Jain bc5e896d35 enhance(webhook): show sender avatar on Slack notifications (#39656)
Closes #39655
2026-10-22 10:56:48 +00:00
d4ecd5eadf fix(api): check unit read permission in issue sub-resource endpoints (#39885)
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>
2026-10-22 12:04:20 +02:00
fixfonandsilverwind aaeb502b30 fix(oauth2): decode form-encoded client credentials in HTTP Basic auth (#39926)
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>
2026-10-22 04:18:43 +00:00
Jeremy Schoemakerandsilverwind cf7050b91d fix(issues): keep one row per issue when sorting by exclusive label order (#39364)
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>
2026-10-22 03:40:31 +00:00
silverwind c1c6bdfedd test(e2e): enable async clipboard testing pref in Firefox (#39838)
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>
2026-10-22 03:16:54 +00:00
Giteabotandsilverwind 7e164fe61a chore(deps): update dependencies, migrate to connectrpc.com/connect v2 (#39854)
Co-authored-by: silverwind <me@silverwind.io>
2026-10-22 01:48:49 +00:00
silverwind 98c613d943 test: fix unit tests failing on repeated runs (#39915)
`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`
2026-10-22 01:27:02 +00:00
GiteaBot ef55965d98 [skip ci] Updated translations via Crowdin 2026-10-22 00:50:21 +00:00
Shivansh Gargandwxiaoguang 0948aed411 refactor(api): load assignees list correctly (#39917)
Correctly handle empty names, upper&lower cases, duplicate names.

Fixes https://github.com/go-gitea/gitea/issues/39916

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-10-21 16:15:43 +00:00
Shudhanshu Singh 33610142c3 chore(maintainers): add SudhanshuMatrix as maintainer (#39922) 2026-10-21 14:54:09 +02:00
Shudhanshu Singhandwxiaoguang a8e1057f5e fix(api): keep milestone due date when it is omitted in edit request (#39869)
`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>
2026-10-21 18:52:33 +08:00
Shudhanshu Singhandwxiaoguang b5e53210c2 fix(lfs): send the default branch as ref in batch download requests (#39891)
Fixes https://github.com/go-gitea/gitea/issues/38085

---------

Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-10-21 03:12:41 -07:00
Ferdinand Maulana Za Fauziandwxiaoguang a6bc03cce1 fix(api): return 4xx for invalid fork repository names (#39909)
Fixes #39908

---------

Signed-off-by: Ferdinand-MZ <ferdinandmaulanazafauzi@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-10-21 17:55:01 +08:00
silverwind 3648598d7d chore(build): run golangci-lint via go run (#39907)
`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`.
2026-10-21 05:30:19 +00:00
silverwind ecae91132b ci: update giteabot to v1.3.0 (#39910) 2026-10-21 04:59:39 +00:00
Artem Lytkinandsilverwind 29a59f6dcf fix(compare): show the diff when a comparison has no commits (#39247)
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>
2026-10-21 04:12:18 +00:00
Aradhya Jain 1244e06d76 enhance(webhook): mention release assets in notifications (#39631)
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>
2026-10-21 01:24:03 +00:00
GiteaBot bb58160aed [skip ci] Updated translations via Crowdin 2026-10-21 00:50:52 +00:00
wxiaoguang 76e88b30c0 fix: use clear error message when failed to parse git version (#39898)
fix #39892
2026-10-20 23:26:56 +00:00
silverwind 82536a3ede fix: off-by-one errors in code comment patches (#39887)
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
2026-10-20 22:10:04 +00:00
Basavaraj S mandsilverwind c52e7c0cd2 fix(packages): reject newline-bearing rubygems dependency metadata (#39782)
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>
2026-10-20 21:18:44 +00:00
silverwind 738ff1d65a refactor(git): replace git stderr matching with exit codes (#39866)
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
2026-10-20 21:00:32 +00:00
silverwind 52eb515751 enhance: improve hover border of colored button groups (#39861)
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
2026-10-20 19:29:38 +00:00
wxiaoguang d7d658a8e9 fix: prevent system users from watching a repository (#39886)
fix #39884
2026-10-20 19:07:20 +00:00
Shivansh Garg 5265238726 fix(api): skip label lookup in ListIssues when no labels filter given (#39890)
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
2026-10-20 18:46:14 +00:00
fixfonandwxiaoguang 35fa0400e9 fix(pulls): tolerate invalid stored review commit_id (#39849)
Fixes #39848

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-10-20 11:03:34 -07:00
edd0c0e2ce feat: add release reactions and a GitHub-like reaction bar (#38415)
Adds emoji reactions to releases and moves the reaction picker of
issues, comments and releases into a GitHub-like reaction bar.

- Releases omit 👎 or 😕
- Drafts and tags can't be reacted to
- Moved menu to tippy
- Added keyboard navigation

Fixes: https://github.com/go-gitea/gitea/issues/34268
Fixes: https://github.com/go-gitea/gitea/issues/16676
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-10-20 15:04:10 +02:00
silverwindandwxiaoguang e645afbb3f refactor: replace Fomantic modal with native dialog (#39846)
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>
2026-10-20 12:32:27 +02:00
Giteabot 7610336d74 chore(deps): update go toolchain directive to v1.27.3 (#39881) 2026-10-20 05:30:28 +02:00
Danny Wardandwxiaoguang 3701fcec84 fix(issues): use unified user display name pattern for more places (#39852)
* Fix #39761

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-10-20 01:13:17 +00:00
GiteaBot f8dd2dd4cc [skip ci] Updated translations via Crowdin 2026-10-20 00:51:42 +00:00
bircniandsilverwind ba4f8fa246 enhance(pull)!: add per-repository default squash merge commit message (#39816)
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>
2026-10-19 09:15:41 +00:00
GiteaBot 458eda0f1d [skip ci] Updated translations via Crowdin 2026-10-19 00:56:21 +00:00
silverwindandwxiaoguang 5264304a34 refactor: carry the API token on the doer (#39690)
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>
2026-10-19 00:34:01 +00:00
silverwind 7e62dda791 chore(actions): update stale go-yaml wrapping comment (#39844)
https://github.com/yaml/go-yaml/pull/441 fixed the wrapping bug this
comment waited for, so reword it. `WithLineWidth(-1)` stays, wrapping
the machine-read payload helps no reader and only adds risk.

Runner: https://gitea.com/gitea/runner/pulls/1324
2026-10-18 18:04:39 +00:00
wxiaoguangandsilverwind f690ea8efd chore: refactor legacy JS init code to use "data-global-init" (#39836)
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>
2026-10-18 13:59:51 +00:00
ae17c14cff fix: add missing checks to several handlers and models (#39839)
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>
2026-10-18 06:29:49 -07:00
silverwind 1031e34987 test: run integration tests on random ports and speed up slow tests (#39842)
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`
2026-10-18 12:56:04 +00:00
Lunny Xiao d0c35bcd58 refactor(git): remove unused TreeCommon embedded struct (#39830)
`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
2026-10-18 12:33:19 +00:00
wxiaoguang 64846db075 fix: use correct template variable on milestone page (#39834)
* fix #39828
2026-10-18 10:42:43 +00:00
Basavaraj S mandwxiaoguang 18d0ee174d fix(mailer): reject incoming email tokens of users who cannot sign in (#39833)
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>
2026-10-18 10:20:00 +00:00
52b18b4903 fix(pull): recover PRs whose recorded merge commit never reached the base repo (#39831)
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>
2026-10-18 09:52:44 +00:00
13ddad6e07 enhance: allow custom watches to bypass on-mention email restriction (#39652)
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>
2026-10-18 09:23:12 +00:00