Follow-up to https://github.com/go-gitea/gitea/pull/39068, which
disabled `modernize` entirely.
- re-enable `modernize`, with only the new `embedlit` rule disabled. It
flattens embedded struct literals across ~145 files, and orphans imports
in 6 of them that the fixer does not remove
- apply the rest of the suite: `errors.AsType`, `reflect.TypeAssert`,
`strings.Cut`, and dropping the legacy import comment
- use the new stdlib `uuid` package, `github.com/google/uuid` becomes
indirect
- use `strings.CutLast` in place of manual `LastIndex` slicing in label
scopes, email domains and the diff tree list
- take the header lint skip dirs from the `go.mod` `ignore` directive
and skip dot-directories, instead of hardcoding the list
Assisted-by: Claude Code:claude-opus-5
Only made some necessary changes:
1. remove `GOEXPERIMENT`, only use jsonv2
1. `make fmt`
* `SigningKey` and `Signature` were affected due to some bugs in the
toolchain, so rewrote them
1. remove or fix fragile magic numbers and strings
* the outputs of image/gzip/zlib packages are different
1. update "nolint" comments for the changed lint behaviors
1. add `tls.MLKEM1024`
Use "binding:TrimSpace" instead of fragile IsEmptyString
And fix a bug in locale's `HasKey`: it should also try the default
language if current language doesn't have the translation key, a new
test is added.
Better than before, still not good enough (more work can be done in the
future)
And add the missing error handling in the PrivateContext "bind"
middleware.
By the way, picked some "TrimSpace" changes from "fix: trim whitespace
from SMTP address and port - #38934" (fix#38926)
- Hash emails with sha256. Gravatar moved to sha256, and both it and
libravatar.org serve the same image for either hash.
- Drop `strk.kbt.io/projects/go/libravatar` for a 46 line inline SRV
lookup. It could not bound or cancel its DNS query and panicked on an
unexpected resolver error. The replacement carries the request context
and a 3s timeout.
- Fix federated avatars querying DNS for every avatar on every render.
`loadAvatarSetting` compared a cache field that was never assigned, so
each call rebuilt the resolver and dropped its cache. That cache is
gone, both settings are read where they are used.
- Migration 348 recreates `email_hash` with a 64 char hash column and a
`hash_type` column, so a later algorithm change can tell old rows apart.
The MD5 rows are unreachable and their `UNIQUE` email index would reject
the SHA256 replacements.
- Fix a re-saved avatar form replacing an uploaded avatar with a random
one.
- Remove the `duoshuo` `GRAVATAR_SOURCE` alias, that service shut down
in 2017.
- Remove dead i18n key.
Fixes: https://github.com/go-gitea/gitea/issues/34284
Fixes: https://github.com/go-gitea/gitea/issues/28110
Docs: https://gitea.com/gitea/docs/pulls/499
Signed-off-by: silverwind <me@silverwind.io>
Migrate away from this thin ssh wrapper module while adding more test
coverage.
Removes `sessionPartial`, which hand-copied the layout of a private
`gliderlabs/ssh` struct and reinterpreted a pointer to it via
`reflect.UnsafePointer` to reach the permissions of the authenticated
connection. The layout is unchecked, so an upstream field reorder would
mismatch silently.
The builtin server only needs the session channel with `exec` and
`shell`. Serving those on `x/crypto` drops the hack and the dependency,
since `PublicKeyCallback` returns permissions per key and `x/crypto`
assigns them only after verifying the signature.
Two benign behavior changes:
1. Internal session handler errors report exit status 1 rather than 0,
so a client no longer reads a failure as success.
1. An unusable host key is fatal at startup instead of being replaced by
an ephemeral one that would trigger an error at the client.
Pairs with https://gitea.com/gitea/runner/pulls/1143.
Gitea depends on `gitea.com/gitea/runner` for exactly two packages:
`act/model` and `act/exprparser`, the workflow model and the expression
evaluator it needs to parse workflows and to build the task payload the
runner consumes. Pulling the whole runner module in for that is heavy
and puts shared code in the repository of one of the two consumers.
Both packages now live in `gitea.dev/actionslib` (`pkg/model`,
`pkg/exprparser`), the module Gitea and the runner already share for the
runner API, so the dependency on the runner repository is dropped here.
### Changes
- `gitea.com/gitea/runner/act/model` ->
`gitea.dev/actionslib/pkg/model`, `.../act/exprparser` ->
`gitea.dev/actionslib/pkg/exprparser` (22 files, import paths only).
- `routers/api/actions/runner/interceptor.go` takes the `x-runner-uuid`
/ `x-runner-token` names from `gitea.dev/actionslib/pkg/protocol`
instead of repeating the literals the runner also has.
- `go.mod`: `gitea.com/gitea/runner` removed.
---------
Signed-off-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Zettat123 <zettat123@gmail.com>
The hardcoded cipher suites and curve preferences date from 2021 and no
longer match what Go ships. All four `SSL_*` are now unset by default
which means "use Go's default".
1. TLS 1.3 is now the default instead of TLS 1.2.
2. Post-quantum key exchange (`X25519MLKEM768`) works.
3. Four `ECDHE-*-CBC-SHA` suites become negotiable on TLS 1.2.
Adds dynamic matrix evaluation to Gitea Actions: a job's
`strategy.matrix` can be built from the outputs of the jobs it needs.
```yaml
jobs:
generate:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set.outputs.result }}
steps:
- id: set
run: echo "result=[1,2,3]" >> $GITHUB_OUTPUT
build:
needs: [generate]
runs-on: ubuntu-latest
strategy:
matrix:
version: ${{ fromJson(needs.generate.outputs.matrix) }}
steps:
- run: echo "building ${{ matrix.version }}"
```
Such a matrix cannot be expanded at planning time, so the job is planned
as a single placeholder and expanded by the job emitter once its needs
finish. Each combination is then gated by `if:` and concurrency as
usual.
- A matrix that resolves to no combination fails the job, as on GitHub.
- Expansion is capped at `MaxJobNumPerRun`.
- Workflows without a needs-dependent matrix are unaffected.
Fixes https://github.com/go-gitea/gitea/issues/25179
---------
Signed-off-by: Pascal Zimmermann <pascal.zimmermann@theiotstudio.com>
Signed-off-by: ZPascal <pascal.zimmermann@theiotstudio.com>
Co-authored-by: Claude <claude-sonnet-4-5@anthropic.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.8) <noreply@anthropic.com>
Co-authored-by: bircni <bircni@icloud.com>
Co-authored-by: Zettat123 <zettat123@gmail.com>
* Closes#36942
* Fixes#19265
Replaces the SSE-based push channel (`/user/events`) with a WebSocket
endpoint (`/-/ws`).
### What changes
- **New `/-/ws` endpoint** (authenticated). One WebSocket per origin,
shared across tabs via a single `SharedWorker`.
- **Pubsub broker** (`services/pubsub`) for fan-out by topic, behind a
`Broker` interface. `MemoryBroker` is the default (single process); a
Redis backend is available for multi-process setups, configured via
`[websocket].PUBSUB_TYPE` / `PUBSUB_CONN_STR`. The internal Gitea queue
was not usable here because it has FIFO/single-consumer semantics.
- **Push-only event production.** Events are emitted by write-triggered
notifiers — `NotificationCountChange`, `PublishStopwatchesForUser`, and
the logout publisher — wired into the existing `notify.Notifier`
interface. No server-side pollers.
- **Typed pub/sub on the client.** `web_src/js/modules/worker.ts` is a
singleton transport; features subscribe per event type via
`onUserEvent('notification-count', cb)` instead of branching on
`event.data.type`.
- **Wire contract** (`UserEventType` union) is shared between the worker
and consumers via `web_src/js/types.ts`, kept in sync with
`services/websocket/events.go`.
- **Client-side periodic polling fallback** kicks in only when the
WebSocket cannot be established (e.g. proxy blocks WS, browser lacks
module-SharedWorker support).
### What's removed
- `modules/eventsource` (SSE manager, run loop, messenger).
- `/user/events` route and `tests/integration/eventsource_test.go`.
- All server-side polling for stopwatches and notification counts.
### Stopwatch multi-tab fix
The navbar stopwatch icon was previously rendered conditionally on `{{if
$activeStopwatch}}`, so tabs loaded before the timer started had no DOM
element to update. The icon and popup are now always rendered (toggled
with `tw-hidden`), and the start/stop/cancel handlers POST silently so
all open tabs reflect the change in real time.
### Deployment note
WebSocket needs the upgrade headers to pass through a reverse proxy,
e.g. for nginx:
```nginx
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
```
Without them the WebSocket cannot be established, and after 3
consecutive failed opens the shared worker signals `push-unavailable`:
the notification count and stopwatch fall back to periodic polling on
the existing `[ui.notification]` timeouts. Real-time push is lost, the
features keep working. The reverse-proxy docs need the same note (see
the `docs-update-needed` label).
---------
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Epid <rexmrj@gmail.com>
- split the go version in `go.mod` into `go` and `toolchain` again
- add a workaround for https://github.com/golang/go/issues/75331 so
`make tidy` never drops `toolchain`
- configure renovate to bump `go` on minor releases and `toolchain` on
every release
- go and toolchain bumps land in a separate, fast-tracked PR, as both
carry security fixes
Replaces: https://github.com/go-gitea/gitea/pull/37846
**Unvalidated version in goproxy ParsePackage**
The module version is read straight from the zip directory path and
never checked, so a crafted upload can leave a newline in it;
`EnumeratePackageVersions` then writes each stored version on its own
line for the `@v/list` endpoint, letting a module advertise fabricated
versions to `go` clients. Validated the parsed version with
`semver.IsValid` inside the parser, matching the version checks the
other package parsers already do.
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
[actions-proto-go v0.6.0](https://gitea.com/gitea/actions-proto-go) adds
a
`capabilities` field to `RegisterRequest` and `DeclareRequest`. This
lets a
runner advertise the transitional `cancelling` capability directly in
the proto
message instead of through the out-of-band mechanism we used while the
proto
bump was pending.
This PR:
- Bumps `gitea.dev/actions-proto-go` to `v0.6.0`.
- Drops the forward-compat `capabilityGetter` type-assertion shim and
the
`runnerRequestHasCancellingCapability` helper, reading
`GetCapabilities()`
directly (now part of the `declareRequest` interface).
- Removes the "capability state unknown → preserve existing value"
branch.
## Why the behaviour change is correct
The shim and the `(hasSupport, known)` two-value return only existed
because the
old proto had no `capabilities` field, so we couldn't tell "runner
doesn't
support it" from "we can't see the field." With v0.6.0 the field is
always
present. Since proto3 repeated fields have no presence, "no capabilities
sent"
now unambiguously means the runner does not advertise the capability, so
a
runner that omits `cancelling` is correctly recorded as
`HasCancellingSupport =
false`.
There is no regression: prior to this bump Gitea was on `v0.5.0`, where
the
type assertion always failed and `HasCancellingSupport` was therefore
never set
from requests — so no runner relied on the preserved-unknown path.
## Compatibility
The change is wire-compatible in both directions of version skew,
because the
new field uses a previously unused field number (8 on `RegisterRequest`,
3 on
`DeclareRequest`) and the transport uses the binary protobuf codec:
- **Old runner → new Gitea:** the runner omits the field; it decodes to
an empty
capability list. Registration/declaration succeed; the runner simply
doesn't
get the cancelling feature.
- **New runner → old Gitea:** the runner sends the field; the old
server's
generated code doesn't know the field number and silently ignores it.
Registration/declaration succeed.
The feature only activates once both server and runner are on `v0.6.0`.
Upgrade `github.com/SaveTheRbtz/zstd-seekable-format-go/pkg` from
`v0.8.3` to `v0.10.0`:
https://github.com/SaveTheRbtz/zstd-seekable-format-go/releases/tag/pkg%2Fv0.10.0
This keeps Gitea's seekable zstd wrapper on the stable v0.10 API while
preserving the existing public `modules/zstd` API.
API migration:
- update `SeekableWriter` and `SeekableReader` internals for the
concrete `*seekable.Writer` and `*seekable.Reader` types introduced by
SaveTheRbtz/zstd-seekable-format-go#264
- update generated dependency metadata after `go mod tidy` removed the
now-unused `github.com/google/btree` transitive dependency
- no Gitea call sites needed changes because `modules/zstd` still
exposes the same constructors and interfaces
Validation:
- `go test ./modules/zstd`
- `make --always-make checks-backend`
---------
Co-authored-by: Giteabot <teabot@gitea.io>
Updates `github.com/urfave/cli/v3` to
[v3.9.0](https://github.com/urfave/cli/releases/tag/v3.9.0) and removes
the renovate pin now that
[urfave/cli#2319](https://github.com/urfave/cli/pull/2319) (the `-c`
help flag parsing fix) is merged.
v3.9.0 prepends the default command name to the root command's args,
which broke the old `Root().Args()` check in `isValidDefaultSubCommand`.
It now uses the command's own `Args()`.
Behavior change: `./gitea web <extra-positional-arg>` now errors with
`unknown command` instead of starting the web server and ignoring the
trailing arg. `web` takes no positional args, so this is stricter (and
arguably more correct) input handling. The intended `./gitea bad-cmd`
rejection is unchanged.
---
This PR was written with the help of Claude Opus 4.7
---------
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
### Description
Replaces all remaining direct `gopkg.in/yaml.v3` imports with
`go.yaml.in/yaml/v4` across models, modules, routers, services, and
integration tests. `gopkg.in/yaml.v3` moves from a direct to an indirect
dependency in `go.mod`.
#### API compatibility
The yaml.Node type, node.Kind/node.Content traversal style
(modules/markup/markdown/convertyaml.go), and the
UnmarshalYAML(*yaml.Node) interface signature
(modules/optional/serialization.go) are all preserved in v4 — no
call-site changes were required beyond the import path.
**Related:**
- https://github.com/go-gitea/gitea/pull/36564#issuecomment-4526536805
---------
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.8) <noreply@anthropic.com>
- Update `github.com/alecthomas/chroma/v2` to `v2.25.0`.
- Migrate `github.com/dlclark/regexp2` to `/v2` (incorporates
https://github.com/go-gitea/gitea/pull/37664); drop the renovate pin.
- Replace the unmaintained `github.com/dimiro1/reply` (the last consumer
of `regexp2` v1 in our own code) with a small built-in reply parser for
incoming mail.
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
Co-authored-by: Nicolas <bircni@icloud.com>
Currently unmaintained package `github.com/jaytaylor/html2text` is
replaced using `replace` directive. Instead, the correct package
`github.com/Necoro/html2text` should be referenced directly in code.
---------
Co-authored-by: Giteabot <teabot@gitea.io>