Add DisplayName, Maintainer, MaintainerURL, InfoURL, TargetVersion, and
PHPMinimum to RepoManifest. These fields were previously only in
UpdateStreamConfig and are now in the manifest as the single source of
truth. Distribution section shown conditionally for joomla/wordpress/
dolibarr platforms. Closes#582 phase 1.
- Add version_prefix field for fork versioning (e.g., v1.26.1-moko.)
- Change platform dropdown from programming languages to deployment
targets (Joomla, Dolibarr, WordPress, Generic, etc.) so template
repos can be mapped to platforms
- Available in settings UI and REST API
- Add version_prefix field for fork versioning (e.g., v1.26.1-moko.)
- Change platform dropdown from programming languages to deployment
targets (Joomla, Dolibarr, WordPress, Generic, etc.) so template
repos can be mapped to platforms
- Available in settings UI and REST API
Add a "Manifest" page in repo settings that stores moko-platform manifest
fields (identity, governance, build) in the database. Includes:
- RepoManifest model with all manifest.xml fields
- Migration v347 adding repo_manifest table
- Auto-detect and migrate .mokogitea/manifest.xml on first settings visit
- Repo settings UI with Identity/Governance/Build sections
- REST API: GET/PUT /api/v1/repos/{owner}/{repo}/manifest
for Actions workflows and moko-platform CLI
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Clear custom field filters when field definitions fail to load,
preventing invisible filtering with no UI to undo
- Log malformed options JSON instead of silently dropping fields
- Extract parseCustomFieldQueryParams helper (web) and
parseAPICustomFieldFilters helper (API) to deduplicate cf_ parsing
- API returns 400 for non-numeric or non-positive cf_ field IDs
- Validate field IDs are positive in web handler
- Add entity_type='issue' to subquery to prevent cross-entity matching
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add the ability to filter issues by custom field values throughout
the entire search stack:
- DB: applyCustomFieldCondition joins custom_field_value with AND
semantics (all specified fields must match)
- Indexer: CustomFieldFilters map passed through SearchOptions and
ToDBOptions
- Web: parse cf_{fieldID}={value} query params, show dropdown
filters in the issue list sidebar for org-level fields
- API: both SearchIssues and ListIssues accept cf_ query params
Closes#496
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- API: return 500 on GetCustomFieldsByOwner failure instead of silently
swallowing the error
- resolveExtensionMetadata: add DownloadGating/KeyPrefix to metadata
struct instead of mutating the caller's cfg pointer (side effect)
- resolveExtensionMetadata: add Description custom field mapping
- Composer: use meta.PHPMinimum instead of bypassing the cascade
- Web form: flash error on custom field save failure instead of silent log
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add `custom_fields` map to IssueTemplate struct so templates can specify
default values (e.g. `Priority: Medium`). On new issue form, org-level
issue-scoped fields appear in the sidebar with template defaults pre-selected.
NewIssuePost saves the values after issue creation. The API create issue
endpoint also accepts `custom_fields` by name.
Closes#493
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
API endpoints:
- GET/POST/DELETE /api/v1/orgs/{org}/custom-fields — org field definitions
- GET/PUT /api/v1/repos/{owner}/{repo}/metadata — repo-scoped field values
- GET/PUT /api/v1/repos/{owner}/{repo}/issues/{index}/custom-fields — issue values
All endpoints use field names as keys (not IDs) for ergonomic access.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The em dash in the TODO comment was encoded as invalid UTF-8, causing
a Go compiler error. Replace with ASCII hyphen.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Comment out custom-fields API routes in api.go that referenced handler
functions from the deleted routers/api/v1/repo/custom_field.go. Remove
the unreferenced modules/structs/custom_field.go and the duplicate
v1_25/v323 migration (superseded by v1_27/v343).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The old API file references non-existent struct names and fields.
Will be rebuilt properly after the web UI is complete.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SECURITY: Add verifyPackageOwnership/verifyKeyOwnership checks to
all API handlers that accept ID parameters. Prevents cross-org
access where an admin of org A could modify org B's license data.
FIX: RepoScope validation now properly parses JSON arrays using
json.Unmarshal instead of strings.Contains. The old approach matched
substrings (repo ID "2" matched inside "12"). Now uses typed int64
comparison.
FIX: Add {{$.CsrfTokenHtml}} to both delete confirmation modal
forms (package and key) in repo and org templates. Without CSRF
tokens, the form-fetch-action POST requests would be rejected.
FIX: HTML-escape release notes in WordPress changelog to prevent
XSS via malicious release note content reaching WP admin dashboards.
FIX: Parse AllowedChannels JSON format before comma-split fallback
to avoid garbage values from splitting JSON arrays by comma.
FIX: Add missing third return value (false) on error path in
validateUpdateKey to prevent compile error.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SECURITY: ValidateLicenseKeyForRepo() now checks the package's
RepoScope field against the requesting repo ID. A package scoped
to repo A will reject keys when accessed from repo B's update feed.
Update server and download gating both use the new function.
Master/internal keys bypass repo scope checks.
RepoScope supports: "all" (any repo), single repo ID string,
or JSON array of repo IDs like ["1","5","12"].
Also adds POST /license-keys/{id}/revoke API endpoint that was
missing from the API but existed in web handlers.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Migration v340: sync all missing columns (key_raw, payment_ref,
last_heartbeat_unix, is_archived, licensing_enabled, download_gating,
support_url, and all extension metadata fields).
Package archiving (#384): add IsArchived field with archive/unarchive
handlers and collapsible "Archived Packages" section in templates.
Existing keys from archived packages continue to work.
Expanded delete permissions (#385): org owners and site admins can
permanently delete packages and keys (previously site admin only).
Search (#392): server-side search across key_prefix, key_raw,
licensee_name, licensee_email, domain_restriction, and payment_ref
via ?q= query parameter on both repo and org licenses pages.
Sortable tables (#390): Fomantic UI sortable class on keys table
with new Domain column showing DomainRestriction per key.
Download gating (#347): three modes — none, prerelease-only, and
all downloads. CheckDownloadGating() intercepts both release
attachment and git archive download handlers.
Support URL (#393): configurable SupportURL field on
UpdateStreamConfig for wiki or external site links.
Changelog XML (#343): ServeChangelogXML endpoint at /changelog.xml
generates Joomla-compatible changelog from release notes. Parses
Keep-a-Changelog markdown sections into <security>, <fix>,
<addition>, <change>, <remove>, <note> XML elements.
API renew (#387): POST /license-keys/{id}/renew endpoint extends
key expiration by package duration.
Closes#384, #385, #386, #387, #389, #390, #392, #393
Refs #343, #346, #347
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- chore: remove stale mustNotBeArchived FIXME (CanEnableEditor no longer exists)
- fix(routes): remove dead /cherry-pick/{sha} route — replaced by /_cherrypick/
- fix(feed): use full ref name instead of ShortName for file feed revision
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- fix(templates): add required validation to issue dropdown fields
- refactor(ts): remove redundant `handled` field from MarkdownHandleIndentionResult
- refactor(go): rename HasOrgOrUserVisible to IsOwnerVisibleToDoer for clarity
Refs #311, #334
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Full namespace migration: update the Go module path and all import
statements from git.mokoconsulting.tech to code.mokoconsulting.tech.
Also updates all URL references in templates, workflows, configs,
tests, and documentation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add key editing, domain enforcement, purchase webhooks, public
validation API, channels multiselect, Joomla downloadkey element,
licensing feature toggle, unified update system, release tag
enforcement, heartbeat tracking, and improved settings UX.
Phase 1: Full key display with AbsoluteShort dates, master package
protection (hide edit/delete in UI, reject in handlers).
Phase 2: Key edit page with template, handlers, and routes for both
repo and org levels. Master keys redirect away.
Phase 3: Domain restriction checking against CSV allowlist,
MaxSites enforcement via CountUniqueDomainsByKey and
IsDomainKnownForKey, dlid query param support for Joomla.
Phase 4: Purchase webhook (POST /license-keys/purchase) with
PaymentRef idempotency. Public validation endpoint
(POST /license-keys/validate) outside auth middleware.
PATCH /license-keys/{id} for API key editing.
Phase 5: Channels multiselect using org UpdateStreamConfig streams
rendered as checkboxes, stored as JSON arrays.
Additional: downloadkey XML element, LicensingEnabled toggle on
UpdateStreamConfig, Dolibarr endpoint unified with key validation,
release tag suffix enforcement, LastHeartbeatUnix field with
TouchHeartbeat, and cleaned-up settings pages.
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>
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>
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>
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>
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>
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>
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>
Fixes nil pointer dereference in BulkSetIssueAssignees — the issue's
Repo field must be loaded before UpdateAssignees calls CanAssignTo.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add four new API endpoints under /repos/{owner}/{repo}/issues/bulk/ for
performing batch operations across multiple issues in a single request.
Each endpoint returns a partial-failure result with per-issue success/failure.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Restore original modules/badge/badge.go (upstream) and adapt our
presets to use GenerateBadge() and the existing Badge type.
- Rename Generate → GenerateRepoBadge to avoid conflict
- Add FormatRepoBadgeSVG for SVG rendering
- Add RenderFlat/RenderFlatSquare methods on Badge
- Fix API handler to use new function names
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The project API endpoints (ListProjects, CreateProject, etc.) were
added to the router but their handler implementations don't exist.
Comment out until implementations are available.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix all 9 remaining files with CurrentRefSubURL field name
- Fix unused 'attempt' variable in action.go
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>
- 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>
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>
Add organization-scoped branch protection rules that cascade to all
repos within the org. Repo-level rules take precedence; org rules
serve as the fallback when no repo rule matches a branch.
- New table: org_protected_branch (migration v332)
- OrgProtectedBranch model with full CRUD operations
- API endpoints: GET/POST/PATCH/DELETE /api/v1/orgs/{org}/branch_protections
- Inheritance via GetFirstMatchProtectedBranchRule() fallback
- InheritedFrom field added to BranchProtection API response
- Org rules use team-based whitelists (no per-user IDs at org level)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Issue
Closes#37217
The error string was getting lost while returning due to `ctx.JSON()`
which cannot serialize the `error` object.
## Fix
Use `ctx.APIError()` to return proper error messages back to the client.