## 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>
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>
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>
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>
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>
Use flex-container layout and wrap the actions runs list with `ui top
attached header` and `ui attached segment` to add a background. Display
the total workflow run count in the header.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Any user with **read access** to a comment can now copy its raw markdown
source via the `···` context menu — no edit permission required.
Closes#36722.
---------
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
I was testing typos-cli and fixed some misspelled wording here.
All changes are internal — no public API fields, database columns,
locale keys, or migration names are affected.
Moved fomantic dropdown css to custom module, tested on the dropdown
devtest page, it renders exactly the same as before while using roughly
50% less CSS. The clean up was very conservative, likely more can be
done in the future.
Also, this fixes a bug present on main branch where dropdown border has
incorrect color on hover.
---------
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* Fix#35685
* Fix#35627
* Fix#31112
Introduce "fipped" config value type, remove unused setting variables.
Make DisableGravatar=true by defult, remove useless config options from
the "Install" page.
The legacy config options are still kept because they are still the
fallback values for the system config options.
---------
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Lazy-load 3 Vue components that are safe to defer (no pop-in effects).
This reduces `index-domready` from 515 KiB to 502 KiB (-2.5%).
The old `vue3-calendar-heatmap` vendor chunk (264 KiB) that previously
loaded on every page is eliminated entirely — it was mostly duplicate
`tippy.js` and `vue` copies that webpack had split out. The actual
heatmap library is only ~12 KiB minified, now inlined into the
`ActivityHeatmap` async chunk.
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
The banner allows site operators to communicate important announcements
(e.g., maintenance windows, policy updates, service notices) directly
within the UI.
The maintenance mode only allows admin to access the web UI.
* Fix#2345
* Fix#9618
---------
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Replace the external easymde.min.css import with an inlined and
lazy-loaded CSS file that uses proper theme variables for border colors.
All EasyMDE/CodeMirror rules are scoped under `.EasyMDEContainer`,
removing the need for !important overrides.
- Fixes easymde borders, these were broken since a while now
- Scope all easymde styles to .EasyMDEContainer
- Inline easymde.min.css and codemirror.css into web_src/css/easymde.css
- Lazy-load the CSS alongside the JS in switchToEasyMDE()
- Fix .editor-toolbar and .CodeMirror border colors to use
--color-input-border matching textarea inputs
- Remove unused gutter, line number, and other unconfigured styles
- Move .editor-loading to codeeditor.css where it belongs
<img width="891" height="518" alt="image"
src="https://github.com/user-attachments/assets/87495de5-7872-4645-90e7-96fe0f782f02"
/>
---------
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Add workflow dependencies visualization
Related to #26062
This PR adds an interactive visualization component that displays job
dependencies in Gitea Actions workflow runs. It helps users understand
complex pipeline structures at a glance, addressing the difficulty of
comprehending dependency chains in current Gitea UI.
---------
Signed-off-by: Semenets V. Pavel <p.semenets@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This is the result of a full-repo review to look for `style` attributes
that can be replaced with tailwind or other methods. I will manually
validate later.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
[`colord`](https://github.com/omgovich/colord) is significantly smaller
than [`tinycolor2`](https://github.com/bgrins/TinyColor) (~4KB vs ~29KB
minified) and ships its own TypeScript types, removing the need for
`@types/tinycolor2`.
Behaviour is exactly the same for our use cases. By using `.alpha(1)` we
force the function to always output 6-digit hex format (it would output
8-digit for non-opaque colors).
---------
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Fixes: https://github.com/go-gitea/gitea/issues/21045
- Move heatmap data loading from synchronous server-side rendering to
async client-side fetch via dedicated JSON endpoints
- Dashboard and user profile pages no longer block on the expensive
heatmap DB query during HTML generation
- Use compact `[[timestamp,count]]` JSON format instead of
`[{"timestamp":N,"contributions":N}]` to reduce payload size
- Public API (`/api/v1/users/{username}/heatmap`) remains unchanged
- Heatmap rendering is unchanged, still shows a spinner as before, which
will now spin a litte bit longer.
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Fixes https://github.com/go-gitea/gitea/issues/24253
When a tasklist checkbox is clicked, the tasklist code [updates
`.raw-content` with latest server
data](7a8fe9eb37/web_src/js/markup/tasklist.ts (L73))
in the DOM after POSTing.
Then when "Edit" is clicked the ComboMarkdownEditor is shown with a
stale value from the previous edit session.
The fix makes it always read from `.raw-content`, no server
syncronization necessary because the value in `.raw-content` is the
latest from the server.
---------
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Persist the two boolean settings in the actions log into `localStorage`
so that they are remembered across page reloads.
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Currently, pressing the space key in the Monaco editor scrolls the page
instead of inserting a space
if the editor is focused. This PR stops the space key event from
propagating to parent elements,
which prevents unwanted page scrolling while still allowing Monaco to
handle space input normally.
Changes:
- disable Monaco editContext
No changes to default editor behavior are needed; Monaco automatically
inserts the space character.
---------
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: silverwind <me@silverwind.io>
Adds three `<select>` controls on top right for indent style, indent
size, and line wrap to the code editor (`_edit`), diff patch editor
(`_diffpatch`) and git hook editor (`/settings/hooks/git/pre-receive`).
The git hooks editor is restyled to wrap the content in a box. Also
included is a bugfix for the git hooks editor where monaco was not
initialized correctly.
---------
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
We've been cutting down on the "striped" tables (where rows are using
alternate row background colors). This completely removes them as I
think such a design looks outdated.
The removal of selectors starting with `.ui[class*="very
basic"].table:not(.striped)` is needed because of a specificity issue in
the CSS where table cells would otherwise render with incorrect padding.
Example of one affected table:
<img width="1027" height="224" alt="image"
src="https://github.com/user-attachments/assets/2f3006ca-99a1-4655-afdb-b7cd9e5f19c7"
/>
Some minor refactors, disable one obsolete lint rule, fix another. The
tribute type issue is not fully fixed and I'm pretty sure it must be an
error in their types.
The "Show more files" button replaces `#diff-incomplete` with newly
loaded diff file boxes.
The inserted HTML may contain htmx attributes, but they are not
processed after insertion.
### Solution
Wrap the incomplete diff placeholder with a temporary wrapper so we can
call `htmx.process()` on the newly inserted content.
After processing, unwrap the wrapper to keep the DOM structure
unchanged.
### Testing
- Open a large PR diff page where `Diff.IsIncomplete` is true
- Click "Show more files"
- Verify newly loaded file boxes behave correctly (htmx-related features
work as expected)
<img width="927" height="278" alt="image"
src="https://github.com/user-attachments/assets/54f2b4f2-c0e1-483c-9e26-79a2838e98ee"
/>
---------
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Fixes #36532
Refined the Enter key trigger logic in the repository filter to prevent
actions during IME composition.
By checking the e.isComposing property, the filter now correctly
distinguishes between "confirming an IME candidate" and "submitting the
search." This prevents premature search triggers when users press Enter
to select Chinese/Japanese characters.
---------
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>