Use .Repository.HTMLURL instead of AppSubUrl+RepoLink so the
copyable update feed URLs include the full domain name.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Major licensing UI improvements:
- Org-level Licenses tab in org menu (visible to org members)
- Org-level Licenses page with full CRUD (packages, keys, revoke)
- Auto-created master key: when admin first visits Licenses page,
a Master (Internal) package + key is auto-generated
- Master keys marked with orange "Master" badge in key list
- Revoking a master key auto-creates a new one on next visit
- Fixed "New Package" button toggle (was using tw-hidden class
that didn't work, now uses style.display)
- IsRepoAdmin set as context data for template access
- Master keys have IsInternal=true, lifetime, all channels
Ref #239
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When an admin first visits the Licenses page, a master license package
and key are automatically created:
- Master package: lifetime, unlimited, all channels, all repos
- Master key: IsInternal=true, never expires
- Raw key shown once with copy instructions
- If master key is revoked, a new one is created on next visit
The master key is always present — revoking it and revisiting the page
generates a fresh one.
Ref #239
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The template couldn't call .Permission.IsAdmin() directly. Set
IsRepoAdmin as a context data variable so the template can use it.
Licenses tab now shows for repo admins even without packages.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Licenses tab was hidden when no packages existed, making it
impossible for admins to find the page to create their first package.
Now shows for repo admins always, and for everyone when packages exist.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add full license management web forms to the Licenses page:
- "New Package" form: name, description, duration, max sites, channels
- "Generate Key" button per package: creates key with auto-expiry
- "Revoke" button per key: deactivates the key
- New key display: shows raw key once with copy instructions
- Update Feed URLs section: copyable Joomla/Dolibarr endpoint URLs
- Admin-only controls: forms only visible to repo admins
Ref #239
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The licenses page was using reqSignIn which blocks API token access
and redirects to login. Use optSignIn so the page is accessible.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fix template error: function "DateTime" not defined. Use
DateUtils.TimeSince which is the correct template function.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a Licenses tab in the repo header that shows when license packages
exist for the repo's owner. The tab displays:
- License packages with name, duration, allowed channels, key count
- Issued keys with prefix, licensee, expiry, and status
Also includes:
- Org-level default update streams with per-repo override (#265)
- Full Joomla channel names in update feeds
- Update Feed button on releases page
- DB migration v336 for update_stream_config table
The Licenses tab appears after Packages in the repo header, gated by
whether any license packages exist for the owner.
Ref #239, #265
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use the full Joomla convention for update stream tag names:
- dev → development
- rc → release-candidate
- alpha, beta, stable unchanged
Add NormalizeChannel() helper that maps shorthand names (dev, rc)
to full names so license key allowed_channels work with either
format. Applied in XML generation, JSON generation, and key
validation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add an "Update Feed" button next to the RSS link on the releases page
that links to the repo's updates.xml endpoint. Only shown on the
releases view (not tags).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Same bug as keys — packages were created with is_active=false
causing all key validation to reject even valid keys.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Keys were created with is_active=false (DB default) because the API
handler didn't explicitly set IsActive. This caused all key validation
to fail.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Clarify that update feeds (updates.xml, dolibarr.json) are always
accessible regardless of the releases visibility setting. The
visibility dropdown controls whether the releases page is browsable
by anonymous visitors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add the same inline visibility control (Private / Public) to the
issues section on the repo settings page. Now wiki, releases, and
issues all have visibility dropdowns.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add per-unit visibility dropdown (Private / Public) directly on the
repo settings page next to each unit's enable checkbox. This replaces
the need to navigate to a separate Public Access settings page.
Supported units: Code, Wiki, Issues, Releases. Each gets a dropdown
that controls AnonymousAccessMode — when set to Public, the unit is
readable by anonymous visitors even on private repos.
Closes#238
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fix two compilation errors in license key API routes:
- reqRepoAdmin() does not exist, use reqAdmin() instead
- m.Delete(handler) needs route pattern: m.Delete("", handler)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fix reqRepoAdmin() -> reqAdmin() and m.Delete(handler) -> m.Delete("", handler)
to match the Gitea API route registration patterns.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace ctx.Bind/ctx.APIErrorValidation (which don't exist on
APIContext) with web.GetForm() pattern used by all other API handlers.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add REST API for managing license packages and keys:
- GET/POST /api/v1/repos/{owner}/{repo}/license-packages
- GET/POST /api/v1/repos/{owner}/{repo}/license-keys
- DELETE /api/v1/repos/{owner}/{repo}/license-keys/{id}
- GET /api/v1/repos/{owner}/{repo}/license-keys/{id}/usage
API structs for create/edit/response, with raw key only returned on
creation. Requires repo admin permissions.
Ref #239
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The WithFileConfig for LandingPage tried to parse the app.ini
LANDING_PAGE string value (e.g. "home") as JSON into a struct,
causing a startup hang. The landing page setting should only be
managed through the dynamic config system (admin UI).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add license key data model and Dolibarr update feed endpoint:
License key system:
- license_package table: subscription tiers with duration, max sites,
repo scope (org-wide or specific repos), and allowed update channels
- license_key table: individual keys with SHA-256 hashed storage,
domain restriction, custom start/end dates, internal/master key flag
- license_key_usage table: tracks update check activity per key
- DB migration v335 creates all three tables
Update server enhancements:
- Dolibarr JSON endpoint at /{owner}/{repo}/updates/dolibarr.json
- License key validation on update endpoints via ?key=MOKO-XXXX param
- Channel filtering: packages restrict which update streams keys access
- Invalid keys get empty XML response (Joomla-compatible "no updates")
- Usage tracking records domain, IP, user agent, version on each check
Key design decisions:
- Org-level master keys: IsInternal=true, package RepoScope="all"
- Keys stored as SHA-256 hashes, raw key only shown at creation
- Packages define allowed channels (e.g. ["stable","rc"] for Pro tier)
- MOKO-XXXX-XXXX-XXXX-XXXX format for license keys
Ref #239
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add GET /{owner}/{repo}/updates.xml that dynamically generates a
Joomla-compatible updates.xml from the repository's releases.
Features:
- Automatically maps release tags to channels (stable/rc/beta/alpha/dev)
- Finds .zip attachments for download URLs, falls back to archive URL
- Emits one entry per channel (latest release wins)
- Extracts version from tag names, strips common prefixes
- Publicly accessible (no auth required) for Joomla update clients
This is Phase 1 of #239 — the core dynamic update feed generation.
Future phases will add license key gating, Dolibarr support, and
repo settings UI.
Ref #239
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fix three gaps that prevented per-unit public access from working on
private repositories:
1. Git HTTP handler (githttp.go): allow anonymous git pull for private
repos when the target unit (code or wiki) has AnonymousAccessMode
set to read. Previously only checked repo.IsPrivate.
2. Permission engine (repo_permission.go): call
finalProcessRepoUnitPermission for anonymous users on private repos
so that unit-level anonymous access modes are populated. Previously
returned early with AccessModeNone, skipping anonymous mode setup.
3. Search/explore (repo_list.go): include private repos that have at
least one unit with anonymous_access_mode > 0 in search results,
so anonymous users can discover repos with public sections.
The existing settings UI at /settings/public_access already allows
configuring per-unit visibility. The home page redirect to the first
readable unit (e.g. wiki) also already works via checkHomeCodeViewable.
Closes#238
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a dynamic config option to set the default landing page for
unauthenticated visitors from Site Administration > Settings. Options:
- Home (default explore page)
- Explore (repository explore)
- Organizations (org explore)
- Login (redirect to login)
- Custom path (any internal URL like /MokoConsulting)
The setting takes effect immediately without restart, using the same
dynamic config system as maintenance mode and web banner. Falls back
to the static LANDING_PAGE setting from app.ini if not configured.
Closes#240
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add push trigger on main branch to deploy-mokogitea.yml so merges
to main automatically deploy to production. When triggered by push,
the version is derived from git describe and environment defaults to
production. Manual workflow_dispatch still works for explicit version
deployments and dev environment targeting.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rebrand the built-in actions bot user from upstream Gitea naming to
MokoGitea branding:
- Name: gitea-actions → mokogitea-actions
- FullName: Gitea Actions → MokoGitea Actions
- Email: teabot@gitea.io → mokogitea-actions[bot]@mokoconsulting.tech
Add backward-compatible name recognition so all three bot name variants
(mokogitea-actions, gitea-actions, github-actions) with optional [bot]
suffix resolve to the same system user.
Add WhitelistActionsUser, MergeWhitelistActionsUser, and
ForcePushAllowlistActionsUser toggles to branch protection rules,
allowing CI/CD workflows to push to protected branches when explicitly
enabled. Previously the actions bot (virtual user ID -2) could never be
added to whitelist because updateUserWhitelist() only validates real
database users.
Closes#233
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add Step 12 to auto-release pipeline that recreates the version branch
from main after each stable release. Also mirrors the version branch
to GitHub alongside main.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add runtime ${APP_NAME} placeholder substitution in locale strings so
all user-facing text reflects the configured APP_NAME from app.ini.
Replace 52 hardcoded locale strings, template literals, HTTP auth
realm headers, and Swagger API titles/descriptions with the
configurable value.
Closes#1
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Backport #37588 by @pandareen
## Summary
Fixes
[go-gitea/gitea#37564](https://github.com/go-gitea/gitea/issues/37564):
when an OIDC provider returns a `picture` claim, Gitea is supposed to
download that image as the user's avatar (if `[oauth2_client]
UPDATE_AVATAR = true`). Two latent bugs prevented this from working
consistently:
1. **Default Go User-Agent rejected by some image hosts.**
`oauth2UpdateAvatarIfNeed` used `http.Get`, which sends `User-Agent:
Go-http-client/1.1`. Hosts like `upload.wikimedia.org` reject that UA
with `403`, and every error path silently returned, so the user was left
with an identicon and **no log line** to diagnose the issue.
2. **Link-account *register* path skipped avatar sync.** First-time OIDC
sign-ins where auto-registration is disabled (or required a
username/password retype) go through `LinkAccountPostRegister`, which
created the user but never called `oauth2SignInSync`. So the avatar /
full name / SSH keys from the IdP were dropped on the floor for those
users, even though the existing-account-link path (`oauth2LinkAccount`)
and the auto-register path (`handleOAuth2SignIn`) both already did the
sync.
## Changes
- `routers/web/auth/oauth.go` — `oauth2UpdateAvatarIfNeed` now uses
`http.NewRequest` + `http.DefaultClient.Do`, sets `User-Agent: Gitea
<version>`, and logs every failure path at `Warn` (invalid URL, fetch
error, non-200, body read error, oversize body, upload error). No silent
failures.
- `routers/web/auth/linkaccount.go` — `LinkAccountPostRegister` now
calls `oauth2SignInSync` after a successful user creation, mirroring the
auto-register and link-existing-account flows.
- `tests/integration/oauth_avatar_test.go` — new
`TestOAuth2AvatarFromPicture` integration test with five sub-cases:
- `AutoRegister_FetchesAvatarFromPictureWithGiteaUA` — happy path,
asserts `use_custom_avatar=true`, an avatar hash is set, exactly one
HTTP request was made, and the request carried a `Gitea ` UA. The mock
server enforces the UA prefix to mirror real-world hosts that reject
Go's default UA.
- `AutoRegister_NonOK_DoesNotUpdateAvatar` — server returns 403; user's
avatar must remain unset.
- `AutoRegister_EmptyPicture_NoFetch` — empty `picture` claim must not
trigger any HTTP request.
- `AutoRegister_UpdateAvatarFalse_NoFetch` — `UPDATE_AVATAR=false` must
not trigger any HTTP request.
- `LinkAccountRegister_FetchesAvatarFromPicture` — guards the
`linkaccount.go` fix; without the new `oauth2SignInSync` call this
assertion fails.
## Test plan
- [x] `go test -tags 'sqlite sqlite_unlock_notify' -run
'^TestOAuth2AvatarFromPicture$' ./tests/integration/ -v` — 5/5 sub-tests
pass.
- [x] Manual: log in as a Keycloak user with `picture` claim pointing at
`https://avatars.githubusercontent.com/u/9919?v=4` — Gitea avatar is
replaced with the GitHub picture.
- [x] Manual: same flow with `https://upload.wikimedia.org/...` —
request now succeeds (or returns a clearly logged `Warn` line if
rate-limited with `429`); previously it silently 403'd.
- [x] Manual: `UPDATE_AVATAR=false` — user keeps the identicon, no
outbound request in container logs.
- [ ] Reviewer: please double-check that no other call sites of
`oauth2UpdateAvatarIfNeed` rely on the old `http.Get` behaviour.
## Related
- Upstream issue: go-gitea/gitea#37564
--------------------------------------------
AI Editor was used in this PR
---------
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: pandareen <7270563+pandareen@users.noreply.github.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Nicolas <bircni@icloud.com>
When multiple workflows are triggered by a single event (e.g. a
pull_request with several matching workflow files), each InsertRun
transaction acquires an X-lock on the repository row via
UpdateRepoRunsNumbers and an index lock on action_run. Two concurrent
transactions can deadlock when each holds one lock and waits for the
other. InnoDB kills the lighter transaction, but handleWorkflows only
logged the error and silently dropped the workflow run — making it
appear as though pull_request events were never fired.
This was the root cause of API-created PRs appearing to not trigger
Actions workflows: the notification pipeline was correct, but the DB
insert was lost to an unretried deadlock.
The fix wraps PrepareRunAndInsert in a retry loop (up to 3 attempts
with exponential backoff) that detects deadlock errors across MySQL,
PostgreSQL, and SQLite. On deadlock, the rolled-back run fields are
reset before the next attempt.
Also adds db.IsErrDeadlock() for cross-engine deadlock detection and
unit tests for the same.
Closes#220
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Allow C++, .NET, version numbers (2.0.1) in wiki filenames.
Clean up isolated plus signs that appear between hyphens.
Examples:
- C++ vs C# -> C++-vs-C.md
- .NET Guide -> .NET-Guide.md
- version 2.0.1 -> version-2.0.1-release.md
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New wiki page titles are now sanitized before creating the git file:
- Spaces and special characters replaced with hyphens
- Consecutive hyphens collapsed to single hyphen
- Leading/trailing hyphens trimmed
Examples:
- "My Page Name" -> "My-Page-Name"
- "API & Docs (v2)" -> "API-Docs-v2"
- "100% Complete!!" -> "100-Complete"
Only affects NEW pages. Existing wiki pages with legacy filenames
(spaces, URL encoding) continue to work — the read path is unchanged.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds a Require2FA toggle to organization settings. When enabled,
org members without 2FA are redirected to the security settings
page with a warning flash message.
Changes:
- New Require2FA field on User model (migration v333)
- Org settings UI checkbox with shield-lock icon
- Check2FARequirement middleware on member-required org routes
- UpdateOptions extended with Require2FA field
Closes#208
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When a user signs in, sends notifications with username, IP address,
user agent, and timestamp. Notifications go through:
- Email to the user's registered address
- ntfy push to the configured topic
Enabled by default, configurable via app.ini:
[login_notification]
ENABLED = true
The notification fires asynchronously (goroutine) so it doesn't
block the login redirect. Hooks into handleSignInFull which is the
single choke point for all auth methods (password, 2FA, OAuth).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Help link added to footer right-links (next to API and Licenses)
- Login logo (login-logo.png) now shown on the signin page, not just
the home page. Hidden via onerror when not uploaded.
- Landing page is set to 'login' so home.tmpl never renders — the
logo needed to be on signin_inner.tmpl instead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The help link was wrapped in {{if not .IsSigned}} which hid it for
logged-in users. Removed the condition so it's always visible.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
octicon-dashboard doesn't exist in Gitea's SVG set, causing the
icon to render as raw text. octicon-meter is the equivalent gauge icon.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Changed details.toggleable-item summary from justify-content:
space-between to gap + margin-left: auto on the chevron. Added
.flex-container-nav .item rule to force left alignment on all
menu items including standalone links.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The compiled CSS bundle doesn't pick up the flexcontainer.css change.
Use inline style with !important on the menu container to override
Fomantic UI's default center alignment.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fomantic UI's vertical menu centers text by default. Added
text-align: left to .flex-container-nav menu items so all
admin sidebar entries align consistently.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Each release attachment now gets its own .sha256 checksum file
(e.g. asset.zip.sha256) instead of a single checksums.sha256 manifest.
Old .sha256 files are cleaned up before regenerating.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Each branding image row now has a Reset button when custom image exists
- Reset removes the custom file, reverting to built-in default
- All admin sidebar menu items now have octicon icons
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Help URL: knowledge base / documentation link
- Support URL: ticket system / email for user support
Both saved to app.ini and applied in-memory immediately.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace built-in logo.png, favicon.png, logo-small.png with Moko
Consulting branding images
- Remove SVG overrides so PNG takes priority
- Set apple-touch-icon.png to favicon for iOS home screen
- Update site manifest to include favicon.png as 256x256 PWA icon
so installed apps show the square brand icon
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Locale changes:
- Renamed "Gitea" -> "MokoGitea" in all user-facing strings across
28 language files (928 references)
- Preserved upstream feature names: "Gitea Actions", "Gitea API",
"gitea.com", "Gitea instances"
Branding page:
- Changed from three-card layout to single-column stacked segments
- Each image type shown inline with preview, label, and upload form
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The org home page template expects .Members, .NumMembers, .Teams,
.IsOrganizationMember, .IsOrganizationOwner, and .IsPublicMember
but the handler only set OrgOverviewMembers and OrgOverviewTeams
(different key names). The sidebar rendered empty because the
template variables were undefined.
Fixed by adding all required data bindings and capturing the
membersIsPublic map (previously discarded) as a callable function.
Closes#183
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a Branding section to Site Administration where admins can upload
custom images for three separate slots:
- Nav icon (logo-small.png) — top-left corner, 30x30px
- Login logo (logo.png) — login page and homepage
- Favicon (favicon.png) — browser tab icon
Changes:
- New admin route: /-/admin/branding with upload forms
- Templates use AssetUrlPrefix instead of hardcoded external URLs
- Nav bar uses logo-small.png with fallback to logo.png
- Uploads save to custom/public/assets/img/ (persists across restarts)
- SVG overrides auto-removed when PNG is uploaded
- Added logo-small.png as default built-in asset
Closes#181
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The previous regex matched across channel boundaries because <version>
appears before <tags> in the XML. Fixed by matching the entire <update>
block containing the target channel tag, then replacing fields within
that block only.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
After a successful production deployment, the deploy workflow now
automatically updates updates.xml on main with the new version,
release URL, and docker image tag for the stable channel.
Dev deployments skip this step — only production releases update
the stable channel.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The deploy workflow now:
1. Enables maintenance mode before building (users see maintenance page)
2. Builds, pushes, and restarts the container
3. Disables maintenance mode after health check passes (if: always)
Uses Gitea's built-in maintenance mode via admin config API.
If the instance is already down, the enable step gracefully warns
instead of failing. The disable step runs even if deploy fails
to avoid leaving the instance in maintenance mode.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The API endpoint POST /releases/{id}/assets bypasses CreateRelease
and UpdateRelease, so checksums were not generated for API uploads.
Added GenerateReleaseChecksums call after successful asset upload.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When a release is created or updated with attachments, automatically
compute SHA256 checksums for every file and attach a checksums.sha256
manifest file. The manifest follows the standard sha256sum format:
<hash> <filename>
Existing checksums.sha256 files are replaced when attachments change.
Checksums are generated for both CreateRelease and UpdateRelease flows.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The update checker now emails the first admin user when a new version
is found on the configured channel. Notifications are deduplicated —
only sent once per new version, not on every cron tick.
- Added NotifyFunc callback in updatechecker module
- Wired to mailer in cron task registration
- Created mail_update.go with plain-text email including version,
channel, release URL, and docker pull command
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a dropdown on the admin dashboard to switch between update streams
(stable, rc, beta, alpha, development) matching the Joomla pattern.
Changes:
- Admin dashboard shows channel selector with descriptions
- POST handler validates and applies channel change in-memory
- Triggers immediate re-check against updates.xml after switch
- updates.xml has all 5 standard channels with descriptions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Matches the Joomla update server pattern used across all Moko repos.
Removed the non-standard 'security' channel. All five standard
channels now present in updates.xml.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rename the Go module path from code.gitea.io/gitea to
git.mokoconsulting.tech/MokoConsulting/MokoGitea across the entire
codebase.
Scope:
- go.mod module declaration
- 2,235 Go source files (import paths)
- Dockerfile WORKDIR and COPY paths
- Swagger API templates
- golangci.yml linter config
External dependencies (code.gitea.io/gitea-vet, code.gitea.io/sdk/gitea,
gitea.com/gitea/act, etc.) are intentionally NOT renamed — they are
separate upstream modules.
Closes#132
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Python heredoc couldn't access shell-local API variable.
Move it to step-level env so os.environ sees it.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The previous workflow had raw XML in bash heredocs that broke the
YAML parser during workflow discovery, causing Gitea to silently
skip the entire workflow.
Fix: all XML generation and API calls now use Python heredocs
(<<'PYEOF') which don't contain characters that confuse the YAML
parser. All github context values passed via env vars instead of
inline expressions in run blocks.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Gitea Actions doesn't reliably evaluate the branches: filter on
pull_request events, causing the workflow to never trigger. Replaced
with a step-level guard that checks github.base_ref at runtime.
Also fixed:
- XML insertion using sed 'e' command instead of shell interpolation
- RC entry removal using Python regex for reliability
- Simplified API URL construction
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Gitea Actions may not evaluate github.event.pull_request.draft
correctly, preventing the workflow from triggering entirely.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Gitea Actions may not evaluate github.event.pull_request.draft
correctly, preventing the workflow from triggering entirely.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix missing https:// protocol in pr-rc-release.yml API URL
- Update comment to remove stale fan-out reference
- Add comprehensive CHANGELOG entry for v1.26.1-moko.04.00.00 release
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When a PR is opened or updated against main:
- Determines RC version from updates.xml base + PR number
- Creates/updates a prerelease on Gitea tagged as v1.26.1-moko.{version}-rc.{PR#}
- Updates updates.xml with RC channel entry pointing to the PR
Admins on the RC update channel will see the PR build as an available
update, matching the Joomla update server pattern.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace JSON API-based update checking with Joomla-style updates.xml
that supports multiple update streams (stable, dev, security).
Changes:
- Add updates.xml at repo root with stable/dev/security channels
following the same XML structure as MokoOnyx and other Joomla repos
- Rewrite updatechecker module to parse XML with channel filtering
- Add CHANNEL setting to [update_checker] config (default: stable)
- Show channel name and docker pull command in admin dashboard banner
Config example:
[update_checker]
ENABLED = true
CHANNEL = stable
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The upstream reading permission fix (#37781) refactored Repository
to have direct IsAdmin/CanWrite/CanRead methods, but our fork's
Repository struct still uses the Permission field for these.
Keep the new CheckTokenScopes function but use ctx.Repo.Permission.*
for the middleware functions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Update deploy workflow description to reflect new versioning scheme:
v{upstream}-moko.{major}.{minor}.{patch} (e.g. v1.26.1-moko.04.00.00)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove .mod -> AMPL mapping from conflictingExtLangMap (AMPL lexer
doesn't exist in chroma v2.23.1, causing a panic when viewing .mod
files). Upstream doesn't have this mapping either.
- Update 500 error page issue link to MokoGitea repo
- Update home page install/license links to MokoGitea repo
- Update theme settings link to MokoGitea repo
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This PR hardens artifact URL signing by encoding signature inputs in an
unambiguous binary payload before computing the HMAC.
What it changes:
- replace direct concatenation-style signing inputs with explicit
payload builders
- encode string fields with a length prefix before appending their bytes
- encode integer fields as fixed-width binary values instead of decimal
text
- apply the same hardening to both:
- Actions Artifact V4 signing in `routers/api/actions/artifactsv4.go`
- artifact download signing in `routers/api/v1/repo/action.go`
- add regression tests that verify distinct field combinations produce
distinct payloads and signatures
Why:
The previous signing logic built HMAC inputs by appending multiple
fields without a strongly structured representation. That kind of
construction can create ambiguity at field boundaries, where different
parameter combinations may serialize into the same byte stream for
signing.
This change removes that ambiguity by constructing a deterministic
payload format with explicit boundaries between fields.
Backport #37707
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
backport #37118
This PR closes remaining `public-only` token gaps in the API by making
the restriction apply consistently across repository, organization,
activity, notification, and authenticated `/api/v1/user/...` routes.
Previously, `public-only` tokens were still able to:
- receive private results from some list/search/self endpoints,
- access repository data through ID-based lookups,
- and reach several authenticated self routes that should remain
unavailable for public-only access.
This change treats `public-only` as a cross-cutting visibility boundary:
- list/search endpoints now filter private resources consistently,
- repository lookups enforce the same restriction even when addressed
indirectly,
- and self routes that inherently expose or mutate private account state
now reject `public-only` tokens.
---
Generated by a coding agent with Codex 5.2
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Backport #37704
This PR hardens OAuth token exchange validation by binding exchanged
credentials to the client and redirect URI that originally obtained
them.
What it changes:
- reject refresh token exchanges when the refresh token belongs to a
different OAuth application
- reject authorization code exchanges when the `redirect_uri` in the
token request differs from the `redirect_uri` stored with the
authorization code
- add integration coverage for:
- authorization code exchange with a mismatched redirect URI
- refresh token reuse across two different dynamically created OAuth
applications
Why:
OAuth authorization codes and refresh tokens must remain bound to the
client context that originally received them. Without those checks:
- a valid authorization code can be redeemed against a different
registered redirect URI of the same client
- a refresh token can be replayed by a different OAuth client
---------
Co-authored-by: Nicolas <bircni@icloud.com>
Backport #37706
This PR tightens several OAuth validation paths related to PKCE
handling, redirect URI normalization, and refresh-token replay safety.
What it changes:
- switch redirect URI comparison to ASCII-only normalization for
exact-match checks, avoiding Unicode case-folding surprises
- harden PKCE verification by:
- allowing PKCE omission only when no challenge data was stored
- rejecting exchanges with a missing verifier when PKCE was used
- rejecting malformed challenge state where a challenge exists without a
valid method
- comparing derived challenges with constant-time string matching
- make refresh-token invalidation counter updates conditional on the
previously observed counter value, so stale refresh state cannot be
accepted after the grant changes
Why:
These checks close gaps where:
- redirect URI comparisons could rely on broader Unicode normalization
than intended
- malformed or incomplete PKCE state could be treated too permissively
- concurrent or stale refresh-token use could advance the same grant
more than once
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Backport #37695 by @lunny
This PR fixes two permission-checking gaps in Git and LFS request
handling.
## What it changes
- keep wiki Git HTTP pushes on the normal write-permission path, even
when proc-receive support is enabled
- revalidate LFS bearer token requests against the current user state
and current repository permissions before allowing access
- add regression coverage for unauthorized wiki HTTP pushes
- add LFS tests for blocked users, revoked repository access, read-only
upload attempts, and valid write access
## Why
- wiki repositories should not inherit the relaxed refs/for handling
used for normal code repositories
- LFS authorization tokens should not remain usable after a user is
disabled or loses repository access
---------
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport of #37662.
---
This PR was written with the help of Claude Opus 4.7
---------
Co-authored-by: Giteabot <teabot@gitea.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Adds a scheduled workflow that runs daily at 08:00 UTC to automatically
detect new bug fixes merged into upstream Gitea's release/v1.26 branch
and create corresponding issues in the MokoGitea tracker.
The workflow:
- Queries GitHub Search API for recently merged fix/security PRs
- Cross-references against existing MokoGitea issues to avoid duplicates
- Creates labeled issues (type: bug, upstream, priority, security)
- Supports manual dispatch with configurable lookback period
Requires secrets: GH_TOKEN (GitHub), GITEA_TOKEN (MokoGitea)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This document explains how to contribute changes to the Gitea project. Topic-specific guides live in separate files so the essentials are easier to find.
| Topic | Document |
| :---- | :------- |
| Backend (Go modules, API v1) | [docs/guideline-backend.md](docs/guideline-backend.md) |
- [Discuss your design before the implementation](#discuss-your-design-before-the-implementation)
- [Issue locking](#issue-locking)
- [Building Gitea](#building-gitea)
- [Styleguide](#styleguide)
- [Copyright](#copyright)
- [Testing](#testing)
- [Translation](#translation)
- [Code review](#code-review)
- [Pull request format](#pull-request-format)
- [PR title and summary](#pr-title-and-summary)
- [Breaking PRs](#breaking-prs)
- [What is a breaking PR?](#what-is-a-breaking-pr)
- [How to handle breaking PRs?](#how-to-handle-breaking-prs)
- [Maintaining open PRs](#maintaining-open-prs)
- [Reviewing PRs](#reviewing-prs)
- [For PR authors](#for-pr-authors)
- [Documentation](#documentation)
- [Developer Certificate of Origin (DCO)](#developer-certificate-of-origin-dco)
</details>
## Introduction
It assumes you have followed the [installation instructions](https://docs.gitea.com/category/installation). \
Sensitive security-related issues should be reported to [security@gitea.io](mailto:security@gitea.io).
For configuring IDEs for Gitea development, see the [contributed IDE configurations](contrib/ide/).
## AI Contribution Policy
Contributions made with the assistance of AI tools are welcome, but contributors must use them responsibly and disclose that use clearly.
1. Review AI-generated code closely before marking a pull request ready for review.
2. Manually test the changes and add appropriate automated tests where feasible.
3. Only use AI to assist in contributions that you understand well enough to explain, defend, and revise yourself during review.
4. Disclose AI-assisted content clearly.
5. Do not use AI to reply to questions about your issue or pull request. The questions are for you, not an AI model.
6. AI may be used to help draft issues and pull requests, but contributors remain responsible for the accuracy, completeness, and intent of what they submit.
Maintainers reserve the right to close pull requests and issues that do not disclose AI assistance, that appear to be low-quality AI-generated content, or where the contributor cannot explain or defend the proposed changes themselves.
We welcome new contributors, but cannot sustain the effort of supporting contributors who primarily defer to AI rather than engaging substantively with the review process.
## Issues
### How to report issues
Please search the issues on the issue tracker with a variety of related keywords to ensure that your issue has not already been reported.
If your issue has not been reported yet, [open an issue](https://github.com/go-gitea/gitea/issues/new)
and answer the questions so we can understand and reproduce the problematic behavior. \
Please write clear and concise instructions so that we can reproduce the behavior — even if it seems obvious. \
The more detailed and specific you are, the faster we can fix the issue. \
It is really helpful if you can reproduce your problem on a site running on the latest commits, i.e. <https://demo.gitea.com>, as perhaps your problem has already been fixed on a current version. \
Please follow the guidelines described in [How to Report Bugs Effectively](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html) for your report.
Please be kind—remember that Gitea comes at no cost to you, and you're getting free help.
### Types of issues
Typically, issues fall in one of the following categories:
-`bug`: Something in the frontend or backend behaves unexpectedly
-`security issue`: bug that has serious implications such as leaking another users data. Please do not file such issues on the public tracker and send a mail to security@gitea.io instead
-`feature`: Completely new functionality. You should describe this feature in enough detail that anyone who reads the issue can understand how it is supposed to be implemented
-`enhancement`: An existing feature should get an upgrade
-`refactoring`: Parts of the code base don't conform with other parts and should be changed to improve Gitea's maintainability
### Discuss your design before the implementation
We welcome submissions. \
If you want to change or add something, please let everyone know what you're working on — [file an issue](https://github.com/go-gitea/gitea/issues/new) or comment on an existing one before starting your work!
Significant changes such as new features must go through the change proposal process before they can be accepted. \
This is mainly to save yourself the trouble of implementing it, only to find out that your proposed implementation has some potential problems. \
Furthermore, this process gives everyone a chance to validate the design, helps prevent duplication of effort, and ensures that the idea fits inside
the goals for the project and tools.
Pull requests should not be the place for architecture discussions.
### Issue locking
Commenting on closed or merged issues/PRs is strongly discouraged.
Such comments will likely be overlooked as some maintainers may not view notifications on closed issues, thinking that the item is resolved.
As such, commenting on closed/merged issues/PRs may be disabled prior to the scheduled auto-locking if a discussion starts or if unrelated comments are posted.
If further discussion is needed, we encourage you to open a new issue instead and we recommend linking to the issue/PR in question for context.
## Building Gitea
See the [development setup instructions](https://docs.gitea.com/development/hacking-on-gitea).
## Styleguide
You should always run `make fmt` before committing to conform to Gitea's styleguide.
## Copyright
New code files that you contribute should use the standard copyright header:
```
// Copyright <current year> The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
```
Afterwards, copyright should only be modified when the copyright author changes.
## Testing
Before submitting a pull request, run all tests to make sure your changes don't cause aregression elsewhere.
All translation work happens on [Crowdin](https://translate.gitea.com).
The only translation that is maintained in this repository is [the English translation](https://github.com/go-gitea/gitea/blob/main/options/locale/locale_en-US.json).
It is synced regularly with Crowdin. \
Other locales on main branch **should not** be updated manually as they will be overwritten with each sync. \
Once a language has reached a **satisfactory percentage** of translated keys (~25%), it will be synced back into this repo and included in the next released version.
The tool `go run build/backport-locale.go` can be used to backport locales from the main branch to release branches that were missed.
## Code review
How labels, milestones, and the merge queue work is documented in [docs/community-governance.md](docs/community-governance.md).
### Pull request format
Please try to make your pull request easy to review for us. \
For that, please read the [*Best Practices for Faster Reviews*](https://github.com/kubernetes/community/blob/261cb0fd089b64002c91e8eddceebf032462ccd6/contributors/guide/pull-requests.md#best-practices-for-faster-reviews) guide. \
It has lots of useful tips for any project you may want to contribute to. \
Some of the key points:
- Make small pull requests. \
The smaller, the faster to review and the more likely it will be merged soon.
- Don't make changes unrelated to your PR. \
Maybe there are typos on some comments, maybe refactoring would be welcome on a function... \
but if that is not related to your PR, please make *another* PR for that.
- Split big pull requests into multiple small ones. \
An incremental change will be faster to review than a huge PR.
- Allow edits by maintainers. This way, the maintainers will take care of merging the PR later on instead of you.
### PR title and summary
In the PR title, describe the problem you are fixing, not how you are fixing it. \
Use the first comment as a summary of your PR. \
In the PR summary, you can describe exactly how you are fixing this problem.
PR titles must follow the [Conventional Commits](https://www.conventionalcommits.org/) format, because PRs are squash-merged and the PR title becomes the resulting commit message:
```text
type(scope)!: subject
```
The allowed types are `build`, `chore`, `ci`, `docs`, `feat`, `fix`, `perf`, `refactor`, `revert`, `style`, and `test`. The generic `chore` type is intentionally not accepted; pick a more descriptive type instead.
Examples:
```text
fix(web): prevent avatar upload crash on empty file
feat(api): add pagination to repo hooks list
ci(workflows): lint PR titles with commitlint
```
Keep this summary up-to-date as the PR evolves. \
If your PR changes the UI, you must add **after** screenshots in the PR summary. \
If you are not implementing a new feature, you should also post **before** screenshots for comparison.
If you are implementing a new feature, your PR will only be merged if your screenshots are up to date.\
Furthermore, feature PRs will only be merged if their summary contains a clear usage description (understandable for users) and testing description (understandable for reviewers).
You should strive to combine both into a single description.
Another requirement for merging PRs is that the PR is labeled correctly.\
However, this is not your job as a contributor, but the job of the person merging your PR.\
If you think that your PR was labeled incorrectly, or notice that it was merged without labels, please let us know.
If your PR closes some issues, you must note that in a way that both GitHub and Gitea understand, i.e. by appending a paragraph like
```text
Fixes/Closes/Resolves #<ISSUE_NR_X>.
Fixes/Closes/Resolves #<ISSUE_NR_Y>.
```
to your summary. \
Each issue that will be closed must stand on a separate line.
### Breaking PRs
#### What is a breaking PR?
A PR is breaking if it meets one of the following criteria:
- It changes API output in an incompatible way for existing users
- It removes a setting that an admin could previously set (i.e. via `app.ini`)
- An admin must do something manually to restore the old behavior
In particular, this means that adding new settings is not breaking.\
Changing the default value of a setting or replacing the setting with another one is breaking, however.
#### How to handle breaking PRs?
If your PR has a breaking change, you must add two things to the summary of your PR:
1. A reasoning why this breaking change is necessary
2. A `BREAKING` section explaining in simple terms (understandable for a typical user) how this PR affects users and how to mitigate these changes. This section can look for example like
```md
## :warning: BREAKING :warning:
```
Breaking PRs will not be merged as long as not both of these requirements are met.
### Maintaining open PRs
Code review starts when you open a non-draft PR or move a draft out of draft state. After that, do not rebase or squash your branch; it makes new changes harder to review.
Merge the base branch into yours only when you need to, for example because of conflicting changes elsewhere. That limits unnecessary CI runs.
Every PR is squash-merged, so merge commits on your branch do not matter for final history. The squash produces a single commit; mergers follow the [commit message format](docs/community-governance.md#commit-messages) in the governance guide.
### Reviewing PRs
Maintainers are encouraged to review pull requests in areas where they have expertise or particular interest.
#### For PR authors
- **Response**: When answering reviewer questions, use real-world cases or examples and avoid speculation.
- **Discussion**: A discussion is always welcome and should be used to clarify the changes and the intent of the PR.
- **Help**: If you need help with the PR or comments are unclear, ask for clarification.
Guidance for reviewers, the merge queue, and the squash commit message format is in [docs/community-governance.md](docs/community-governance.md).
## Documentation
If you add a new feature or change an existing aspect of Gitea, the documentation for that feature must be created or updated in another PR at [https://gitea.com/gitea/docs](https://gitea.com/gitea/docs).
**The docs directory on main repository will be removed at some time. We will have a yaml file to store configuration file's meta data. After that completed, configuration documentation should be in the main repository.**
## Developer Certificate of Origin (DCO)
We consider the act of contributing to the code by submitting a Pull Request as the "Sign off" or agreement to the certifications and terms of the [DCO](DCO) and [MIT license](LICENSE). \
No further action is required. \
You can also decide to sign off your commits by adding the following line at the end of your commit messages:
```
Signed-off-by: Joe Smith <joe.smith@email.com>
```
If you set the `user.name` and `user.email` Git config options, you can add the line to the end of your commits automatically with `git commit -s`.
We assume in good faith that the information you provide is legally binding.
# Contributing to Moko Consulting Projects
Thank you for your interest in contributing. All Moko Consulting repositories follow this universal workflow and version policy.
## Branching Workflow
```
feature/* ──PR──> dev ──draft PR──> (renamed to rc) ──merge──> main
```
### Step by step
1.**Create a feature branch** from `dev`:
```bash
git checkout dev && git pull
git checkout -b feature/my-change
```
2. **Work and commit** on your feature branch. Push to origin.
3. **Open a PR**: `feature/my-change` → `dev`. After review and checks, merge it.
4. **When ready for release**, open a **draft PR**: `dev` → `main`.
- This automatically renames the source branch to `rc` (release candidate)
- An RC pre-release is built and uploaded
5. **Alpha and beta branches** are created by manually renaming the branch before the RC stage:
- Rename `dev` to `alpha` for early testing → alpha pre-release is built
- Rename `alpha` to `beta` for feature-complete testing → beta pre-release is built
- When the draft PR is created, the branch is renamed to `rc`
6. **Once PR checks pass** on the `rc` branch, mark the PR as ready and merge to `main`.
7. **Merging to main** triggers the stable release pipeline:
- Minor version bump (e.g., `02.09.xx` → `02.10.00`)
- Stability suffix stripped (clean version)
- Gitea release created with ZIP/tar.gz packages
- `updates.xml` updated (Joomla extensions)
- `dev` branch recreated from `main`
### Branch summary
| Branch | Purpose | Created by |
|--------|---------|-----------|
| `feature/*` | New features and fixes | Developer |
| `dev` | Integration branch | Auto-recreated after release |
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.