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 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>
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>
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>
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>
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>
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>
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 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>
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 #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>
InsertRun passed nil for the attempt parameter to
EvaluateRunConcurrencyFillModel, which then dereferenced the nil
pointer at concurrency.go:39 when writing ConcurrencyGroup and
ConcurrencyCancel fields. This caused a server panic whenever a PR was
created via the API on a repo with workflow-level concurrency
configured.
The fix:
- Creates an ActionRunAttempt struct in InsertRun before calling
EvaluateRunConcurrencyFillModel, and reuses it for
PrepareToStartRunWithConcurrency
- Updates EvaluateRunConcurrencyFillModel to write concurrency fields
to both the run (for DB persistence) and the attempt (for in-memory
concurrency checks), with a nil guard on the attempt
- Fixes TestEvaluateRunConcurrency_RunIDFallback which had the wrong
argument count and was not testing the attempt path
Closes#136
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace removed upstream Gitea update checker with MokoGitea-native
version that checks our own releases API.
- New module: modules/updatechecker/ — fetches latest release from
git.mokoconsulting.tech, compares semver, caches result
- Cron task: runs every 24h (and at startup)
- Admin dashboard: shows green banner when update available
- Configurable via [update_checker] in app.ini
Closes#74
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Restore context_template.go from commit 82bfde2a37 which added:
- ScriptImport() — generates script tags with CSP nonces
- CspScriptNonce() — generates per-request nonces
- HeadMetaContentSecurityPolicy() — CSP meta header
- CurrentWebBanner() — web banner support
- globalVars — cached script import configuration
These methods were missing from our manual TemplateContext definition,
causing "ScriptImport is not a method" runtime template errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- gocron v2.19.1 uses LastRun() not LastRunStartedAt()
- renderhelper.RepoFileOptions uses CurrentRefPath not CurrentRefSubURL
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix ToActionWorkflowRun calls in routers and services/actions
- Fix PrepareToStartRunWithConcurrency 3-value return + type mismatch
- Fix PrepareToStartJobWithConcurrency 3-value return in run.go
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add ConcurrencyGroup and ConcurrencyCancel fields to ActionRun
- Add GetConcurrentRunsAndJobs query function
- Fix PrepareToStartJobWithConcurrency 3-value return
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace 9 more files still using gitea.com/gitea/runner/act/model
with github.com/nektos/act/pkg/model (resolved via replace directive)
- Fix ToActionWorkflowRun call: args were (ctx, run, nil) but
signature is (ctx, repo, run)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- structs is imported as 'api' — use api.UserVisibility, api.AccessLevelName
- Fix remaining t.Message on line 731 (sed missed non-parenthesized usage)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The type was used throughout services/context but never defined —
likely lost during upstream merge. It's a map[string]any that
implements context.Context.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
MokoGitea now recognizes .mokogitea/ as a first-class directory for:
- Workflow files (.mokogitea/workflows/) with highest priority
- README rendering from .mokogitea/ directory
- Repository template files (.mokogitea/template)
- Vendor path exclusion
The .gitea and .github directories remain supported for compatibility.
Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Merges 356 commits from upstream Gitea v1.26.1 (bugfix release).
Resolved conflicts in templates by keeping our HelpURL changes,
all other conflicts resolved by taking upstream.
Closes#70
Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove upstream Gitea update checker, replace all docs.gitea.com references
with configurable HelpURL, rebrand default APP_NAME to MokoGitea, enforce
dot-prefixed repo privacy at creation time (create, fork, push-create), and
add system repo explanation in settings UI.
Closes#75, closes#76
Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Repositories with names starting with "." are now treated as system
repositories that are always private and cannot be made public. This is
enforced at every code path: API create, web create, migrate, template
create, push-to-create, API edit, web settings, and public access
settings. On creation paths, privacy is silently forced. On edit paths,
a clear error is returned.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When a workflow job failed, the API response reported all steps as
failed — even steps that had completed successfully before the failing
step. `ToActionWorkflowJob` was calling `ToActionsStatus(job.Status)`
for every step instead of `ToActionsStatus(step.Status)`, so the job's
overall conclusion was propagated to each step.
Each `ActionTaskStep` has its own `Status` field that tracks the actual
outcome of that step independently of the job result.
---------
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
fixes adding collaborative owners in Actions settings when the user or
organization name contains capital letters.
Fixes#37548
---------
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>