## Overview
This PR introduces granular permission controls for Gitea Actions tokens
(`GITEA_TOKEN`), aligning Gitea's security model with GitHub Actions
standards while maintaining compatibility with Gitea's unique repository
unit system.
It addresses the need for finer access control by allowing
administrators and repository owners to define default token
permissions, set maximum permission ceilings, and control
cross-repository access within organizations.
## Key Features
### 1. Granular Token Permissions
- **Standard Keyword Support**: Implements support for the
`permissions:` keyword in workflow and job YAML files (e.g., `contents:
read`, `issues: write`).
- **Permission Modes**:
- **Permissive**: Default write access for most units (backwards
compatible).
- **Restricted**: Default read-only access for `contents` and
`packages`, with no access to other units.
- ~~**Custom**: Allows defining specific default levels for each unit
type (Code, Issues, PRs, Packages, etc.).~~**EDIT removed UI was
confusing**
- **Clamping Logic**: Workflow-defined permissions are automatically
"clamped" by repository or organization-level maximum settings.
Workflows cannot escalate their own permissions beyond these limits.
### 2. Organization & Repository Settings
- **Settings UI**: Added new settings pages at both Organization and
Repository levels to manage Actions token defaults and maximums.
- **Inheritance**: Repositories can be configured to "Follow
organization-level configuration," simplifying management across large
organizations.
- **Cross-Repository Access**: Added a policy to control whether Actions
workflows can access other repositories or packages within the same
organization. This can be set to "None," "All," or restricted to a
"Selected" list of repositories.
### 3. Security Hardening
- **Fork Pull Request Protection**: Tokens for workflows triggered by
pull requests from forks are strictly enforced as read-only, regardless
of repository settings.
- ~~**Package Access**: Actions tokens can now only access packages
explicitly linked to a repository, with cross-repo access governed by
the organization's security policy.~~ **EDIT removed
https://github.com/go-gitea/gitea/pull/36173#issuecomment-3873675346**
- **Git Hook Integration**: Propagates Actions Task IDs to git hooks to
ensure that pushes performed by Actions tokens respect the specific
permissions granted at runtime.
### 4. Technical Implementation
- **Permission Persistence**: Parsed permissions are calculated at job
creation and stored in the `action_run_job` table. This ensures the
token's authority is deterministic throughout the job's lifecycle.
- **Parsing Priority**: Implemented a priority system in the YAML parser
where the broad `contents` scope is applied first, allowing granular
scopes like `code` or `releases` to override it for precise control.
- **Re-runs**: Permissions are re-evaluated during a job re-run to
incorporate any changes made to repository settings in the interim.
### How to Test
1. **Unit Tests**: Run `go test ./services/actions/...` and `go test
./models/repo/...` to verify parsing logic and permission clamping.
2. **Integration Tests**: Comprehensive tests have been added to
`tests/integration/actions_job_token_test.go` covering:
- Permissive vs. Restricted mode behavior.
- YAML `permissions:` keyword evaluation.
- Organization cross-repo access policies.
- Resource access (Git, API, and Packages) under various permission
configs.
3. **Manual Verification**:
- Navigate to **Site/Org/Repo Settings -> Actions -> General**.
- Change "Default Token Permissions" and verify that newly triggered
workflows reflect these changes in their `GITEA_TOKEN` capabilities.
- Attempt a cross-repo API call from an Action and verify the Org policy
is enforced.
## Documentation
Added a PR in gitea's docs for this :
https://gitea.com/gitea/docs/pulls/318
## UI:
<img width="1366" height="619" alt="Screenshot 2026-01-24 174112"
src="https://github.com/user-attachments/assets/bfa29c9a-4ea5-4346-9410-16d491ef3d44"
/>
<img width="1360" height="621" alt="Screenshot 2026-01-24 174048"
src="https://github.com/user-attachments/assets/d5ec46c8-9a13-4874-a6a4-fb379936cef5"
/>
/fixes #24635
/claim #24635
---------
Signed-off-by: Excellencedev <ademiluyisuccessandexcellence@gmail.com>
Signed-off-by: ChristopherHX <christopher.homberger@web.de>
Signed-off-by: silverwind <me@silverwind.io>
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: ChristopherHX <christopher.homberger@web.de>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Zettat123 <zettat123@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This PR matches GitHub's behavior more closely on how to render Markdown
images in light/dark mode.
Images with source suffix `#gh-dark-mode-only` / `#gh-light-mode-only`
will only show when the correct theme is requested.
Closes: #35545
---------
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
When creating a new repository and copying issue labels from a template,
the explicit sort order of exclusive labels was previously being lost
(resetting to 0). This fix ensures that the original sort order for
exclusive labels (e.g., 1, 2) is properly copied and retained in the
newly created repository.
Fixes#36463
---------
Signed-off-by: Paulo Chen <paulochen@tecnico.ulisboa.pt>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
## Summary
Two bug fixes for `contrib/upgrade.sh` found during a real-world upgrade
from 1.24.3 to 1.25.5 on Fedora.
---
### Fix 1: GPG key import fails when HKP port 11371 is blocked (closes
#36928)
**Before:**
```bash
gpg --keyserver keys.openpgp.org --recv 7C9E68152594688862D62AF62D9AE806EC1592E2
```
This uses HKP port **11371**, which is blocked by many firewalls. The
upgrade aborts with:
```
gpg: keyserver receive failed: Connection timed out
```
**After:**
```bash
curl -fsSL --connect-timeout 10 \
"https://keys.openpgp.org/vks/v1/by-fingerprint/7C9E68152594688862D62AF62D9AE806EC1592E2" \
| gpg --import \
|| gpg --keyserver keyserver.ubuntu.com --recv 7C9E68152594688862D62AF62D9AE806EC1592E2 \
|| gpg --keyserver keys.openpgp.org --recv 7C9E68152594688862D62AF62D9AE806EC1592E2
```
Same `keys.openpgp.org` server, same key — but fetched over **HTTPS port
443** which is universally accessible. Keyservers remain as fallbacks.
---
### Fix 2: Gitea fails to start after upgrade on SELinux systems (closes
#36929)
**Problem:** After `mv`-ing the binary from `$giteahome` to
`/usr/local/bin/gitea`, the file retains the SELinux context of the
source directory. Systemd refuses to execute it, exiting with
`status=203/EXEC`.
**Fix:** Add a `restorecon` call guarded by `command -v` so it is a
no-op on non-SELinux systems:
```bash
command -v restorecon &>/dev/null && restorecon -v "$giteabin" || true
```
Verified: `restorecon -v /usr/local/bin/gitea` immediately restored
service on the affected machine.
---------
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Replace the fomantic search.css (520 lines) and modal.css (698 lines)
with minimal first-party modules containing only the rules actually
used. Hardcoded colors are replaced with theme variables, and the
base.css overrides are merged directly into the new modules.
With this change, all original Fomantic CSS is now gone.
**search.css**: 520 → 85 lines
**modal.css**: 698 → 329 lines
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Enable swagger-ui's dark mode support added in
https://github.com/swagger-api/swagger-ui/pull/10653. Background colors
match gitea, link colors match swagger-ui.
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Replace the `@github/relative-time-element` npm dependency with a
vendored, simplified implementation.
- Support 24h format rendering [PR
329](https://github.com/github/relative-time-element/pull/329)
- Enable `::selection` styling in Firefox [PR
341](https://github.com/github/relative-time-element/pull/341)
- Remove timezone from tooltips (It's always local timezone)
- Clean up previous `title` workaround in tippy
- Remove unused features
- Use native `Intl.DurationFormat` with fallback for older browsers,
remove dead polyfill
- Add MIT license header to vendored file
- Add unit tests
- Add dedicated devtest page for all component variants
---------
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude claude-opus-4-6 20250630 <noreply@anthropic.com>
Add `SetDefaultValues()` call to ensure PageSize is bounded, preventing
potential excessive memory allocation from unbounded pagination
parameters.
Fixes CodeQL alert
[#188](https://github.com/go-gitea/gitea/security/code-scanning/188).
All other 49 open alerts were false-positives and are dismissed with
appropriate comments.
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
This PR migrates the web Actions run/job routes from index-based
`runIndex` or `jobIndex` to database IDs.
**⚠️ BREAKING ⚠️**: Existing saved links/bookmarks that use the old
index-based URLs will no longer resolve after this change.
Improvements of this change:
- Previously, `jobIndex` depended on list order, making it hard to
locate a specific job. Using `jobID` provides stable addressing.
- Web routes now align with API, which already use IDs.
- Behavior is closer to GitHub, which exposes run/job IDs in URLs.
- Provides a cleaner base for future features without relying on list
order.
- #36388 this PR improves the support for reusable workflows. If a job
uses a reusable workflow, it may contain multiple child jobs, which
makes relying on job index to locate a job much more complicated
---------
Signed-off-by: Zettat123 <zettat123@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Add `--concurrency 2` to all ESLint invocations in the Makefile. ESLint
v9 supports multi-threaded linting via worker threads.
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Hey, I bumped Go to 1.26.1 and fixed a couple of things I ran into while
poking around.
### Changes
- Bump go.mod from 1.26.0 to 1.26.1 (security patch)
- Bump golangci-lint from v2.10.1 to v2.11.2
- Run make tidy, fmt, lint-go
---------
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Cache the final rendered `template.HTML` output for SVG icons that use
non-default size or class parameters using `sync.Map`.
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
If a file is marked as viewed in a PR and all changes to those file are
reverted afterwards, the file is still stored as viewed in the db, which
causes an incorrect viewed files counter
---
<img width="468" height="139" alt="image"
src="https://github.com/user-attachments/assets/f13bf161-142d-49a9-8425-3884ee7abb84"
/>
1. Use `textContent` instead of `innerHTML` to fix
https://github.com/go-gitea/gitea/security/code-scanning/170.
2. Clean up surrounding code to remove unnecessary `if` checks on
elements that are guaranteed to exist.
---------
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
`util.URLJoin` was deprecated with unclear semantics (path normalization
via `url.Parse`/`ResolveReference` that surprised callers). This removes
it entirely and replaces all usages with straightforward `"/"` string
concatenation.
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wxiaoguang <2114189+wxiaoguang@users.noreply.github.com>
1. Copy dependency manifests before the full source copy so that
dependency installation gets its own cached layer. When only source code
changes, the dependency layers are reused.
2. Remove the `GOPROXY=direct` override which was bypassing the Go
module proxy, causing build failures when git servers are unreachable.
The Go default (`https://proxy.golang.org,direct`) is now used instead.
---------
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
The logic of "URLJoin" is unclear and it is often abused.
Also:
* Correct the `resolveLinkRelative` behavior
* Fix missing "PathEscape" in `ToTag`
* Fix more FIXMEs, and add new FIXMEs for newly found problems
* Refactor "auth page common template data"
Principles: let the caller decide what it needs, but not let the
framework (middleware) guess what it should do.
Then a lot of hacky code can be removed. And some FIXMEs can be fixed.
This PR introduces a new kind of middleware: "PreMiddleware", it will be
executed before all other middlewares on the same routing level, then a
route can declare its options for other middlewares.
By the way, allow the workflow badge to be accessed by Basic or OAuth2
auth.
Fixes: https://github.com/go-gitea/gitea/pull/36830
Fixes: https://github.com/go-gitea/gitea/issues/36859
Automated changes by the
[update-flake-lock](https://github.com/DeterminateSystems/update-flake-lock)
GitHub Action.
```
Flake lock file updates:
• Updated input 'nixpkgs':
'github:nixos/nixpkgs/dd9b079' (2026-02-27)
→ 'github:nixos/nixpkgs/aca4d95' (2026-03-06)
```
### Running GitHub Actions on this PR
GitHub Actions will not run workflows on pull requests which are opened
by a GitHub Action.
**To run GitHub Actions workflows on this PR, close and re-open this
pull request.**
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Eliminate a few database queries on all issue and pull request pages by
moving mention autocomplete data to async JSON endpoints fetched
on-demand when the user types `@`.
See https://github.com/go-gitea/gitea/pull/36739#issuecomment-3963184858
for the full table of affected pages.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.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
Make `handlePullRequestAutoMerge` correctly check the
permissions of the merging user against pr.BaseRepo.
---------
Co-authored-by: Michael Hoang <enzime@users.noreply.github.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
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>
* Use base64.RawURLEncoding to avoid equal sign
* using the nodejs package they seem to get lost
* Support uploads with unspecified length
* Support uploads with a single named blockid
* without requiring a blockmap
---------
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
The design of DefaultShowFullName has some problems, which make the UI
inconsistent, see the new comment in code
This PR does a clean up for various legacy problems, and clarify some
"user name display" behaviors.
---------
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>