Release: org-wide governance series (#727) — dev → main #733
Open
jmiller
wants to merge 34 commits from
dev into main
pull from: dev
merge into: :main
:main
:dev
:feature/749-release-notes-from-a-curated-release-not
:fix/rebrand-wiki-docs
:worktree-agent-acb0cede999748165
:feature/744-feat-let-issue-templates-set-mokogitea-f
:feature/745-org-default-teams-add-protected-option-b
:feature/746-auto-add-the-actions-bot-to-the-ci-cd-te
:feature/747-add-a-dedicated-system-api-automation-bo
:feature/738-expand-openapi-spec-mcp-tooling-for-org-
:feature/722-cleanup-and-standardization-of-issue-tem
:feature/723-feat-issue-and-pull-request-voting-upvot
:feature/725-enforce-dot-prefixed-repositories-are-al
:feature/727-org-level-branch-protection-is-stored-bu
:feature/secret-scanning
:rc
:rc/v1.26.1-moko.06.07.02
:rc/v1.26.1-moko.06.07.03
:rc/v1.26.1-moko.06.07.01
:rc/v1.26.1-moko.06.07
:rc/v1.26.1-moko.06.06.02
:rc/v1.26.1-moko.06.06.01
:rc/v1.26.1-moko.06.06
:rc/v1.26.1-moko.06.05.01
:rc/v1.26.1-moko.06.05
:rc/v1.26.1-moko.06.04
:rc/v1.26.1-moko.06.03
:rc/05.06.00
:rc/05.03.03
:rc/04.01.00
:rc/05.03.02
:rc/05.03.01
:rc/05.03.00
:rc/05.01.00
:rc/05.02.02
:rc/05.02.01
:rc/05.01.01
:rc/05.02.00
:rc/05.01.02
:rc/05.03.04
:rc/05.03.05
:rc/05.03.06
:rc/05.03.08
:rc/05.04.00
:rc/05.05.00
No Reviewers
Labels
Clear labels
breaking-change
ci-cd
config
dependencies
deploy-failure
docker
documentation
feature: wiki
good first issue
health-check
help wanted
mokostandards
push-failure
security
size/l
size/m
size/s
size/xl
size/xs
standards-drift
standards-update
sync-failure
tech-debt
upstream
upstream
work-in-progress
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
Breaking API or behavior change
CI/CD pipeline changes
Configuration changes
Dependency updates
Deployment failed
Docker/container changes
Documentation changes
Wiki system enhancements
Good for newcomers
Repo health check result
Extra attention needed
Related to MokoStandards framework
Git push operation failed
Security vulnerability or hardening
200-500 lines changed
50-200 lines changed
10-50 lines changed
500+ lines changed
< 10 lines changed
Deviates from MokoStandards
MokoStandards compliance update
Sync or mirror failed
Technical debt and TODO/FIXME items
Inherited from upstream Gitea
Draft or incomplete work
Something is not working
This issue or pull request already exists
New feature
Need some help
Something is wrong
More information is needed
This won't be fixed
No labels
Priority
-
Type
-
Milestone
No items
No Milestone
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: MokoConsulting/MokoGitea-Fork#733
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.
Delete Branch "dev"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Promotes the org-wide governance series (issue #727) from
devtomain. This is the consolidation of the five stacked PRs already merged todev(#728–#732).Contents (dev over main: 13 commits)
AddTeamMemberchoke pointdevcommit (issue-template edit)Validation status (please read before merging)
dev's tip:Lint & Validate,Validate PR,Secret Scan,Branch Policyall passed. TheProject CI / Testsjob stayed stuck "Blocked by required conditions" — the chronic runner-queue stall, not a code failure — so a definitivego testrun is still owed. Recommend kicking the runners for a clean Tests pass before merging to main.Merging this cuts a stable release to
main. Review below.https://claude.ai/code/session_01Wsno14cxE49MstXFs9G5KT
Adds org-level tag protection as a parallel to org-level branch protection. An org tag rule is {NamePattern, AllowlistTeamIDs}; it cascades to every repo in the org and layers on top of the repo's own protected tags — a tag is controllable (push/delete) only if allowed at BOTH levels (fail-closed). - models/git/org_protected_tag.go: OrgProtectedTag model + CRUD + ToProtectedTag() (reuses the ProtectedTag matcher/allowlist logic) + IsUserAllowedToControlTagInRepo() which ANDs the repo decision with the org decision. Migration 363. - API: /orgs/{org}/tag_protections CRUD (routers/api/v1/org/tag_protection.go, DTOs in modules/structs/org_tag.go, wired in api.go). - Enforcement: the git push/delete hook (hook_pre_receive.go) and the two release paths (release.go create/delete) now call the layered check, so no per-site tag logic changes beyond swapping the helper. - View: the repo Tag settings page lists inherited org tag rules read-only. Stacked on #728 (branch-protection PR) for migration ordering — merge #728 first. Swagger annotations omitted (can't regenerate the swagger JSON without the toolchain); routes still register. Note: no Go toolchain available locally, so not compiled/gofmt'd/tested here. Hand-verified: gofmt (tabs, no blank-in-block, struct alignment), template nesting balances, all .Rule fields exist on OrgProtectedTag, all locale keys defined, JSON valid, migration contiguous (363). Claude-Session: https://claude.ai/code/session_01Wsno14cxE49MstXFs9G5KTAdds a single per-org push policy that cascades to every repo of the org and is enforced in the pre-receive hook: - Branch/tag name conventions (glob) — a pushed ref name must match. Fail-closed. - Mandatory secret-scanning block-on-push — org can force secret blocking that a repo cannot disable (overrides the per-repo scanner config in the orchestrator). - Max pushed-file size — rejects a tip tree containing a blob over the limit. - Blocked file-path patterns — rejects pushes changing matching paths (reuses pull_service.CheckFileProtection). The two content checks (blocked paths, max size) FAIL OPEN on any error so a policy/parsing bug can never wedge all pushes; naming is fail-closed. - models/git/org_push_policy.go: OrgPushPolicy model + CRUD + matchers + GetOrgPushPolicyForRepo. Migration 364. - API: GET/PATCH/DELETE /orgs/{org}/push_policy (routers/api/v1/org/push_policy.go, DTOs in modules/structs/org_push_policy.go, wired in api.go). - Enforcement: routers/private/hook_pre_receive.go (branch: naming + blocked paths + max size; tag: naming) and services/security/orchestrator.go (secret mandate). Deferred: a repo-facing read-only view of the org push policy (it is an org-wide config, not per-repo overlay rules; readable via the API for now). Stacked on #729/#728 for migration ordering (this = 364). Swagger annotations omitted (can't regenerate without the toolchain). Note: no Go toolchain available locally, so not compiled/gofmt'd/tested here. Hand-verified: gofmt (tabs, no blank-in-block), escape sequences in the ls-tree parser, imports used, migration contiguous (364), fail-open on content checks. Claude-Session: https://claude.ai/code/session_01Wsno14cxE49MstXFs9G5KTAdds a single per-org repository-defaults config, applied to a repo when it is created in or transferred into the org via a notifier (services/org): - ForcePrivate — force new/transferred repos private (Repository.IsPrivate). - PR defaults (when ApplyPRDefaults) — allowed merge styles, default merge style, and auto-delete-branch-after-merge, written to the repo's pull-requests unit config via repo_service.UpdateRepositoryUnits. Best-effort: the notifier logs and swallows errors, so a defaults bug can never break repository creation or transfer. - models/git/org_repo_defaults.go: OrgRepoDefaults model + CRUD + migration 365. - API: GET/PATCH/DELETE /orgs/{org}/repo_defaults. - services/org/notifier.go: CreateRepository/TransferRepository -> apply defaults; registered from routers/init.go (org_service.Init()). Stacked on #730/#729/#728 for migration ordering (this = 365). Swagger omitted. Note: no Go toolchain available locally, so not compiled/gofmt'd/tested here. Hand-verified: gofmt (tabs, no blank-in-block, struct/DTO alignment), imports used, no Init() collision in services/org, migration contiguous (365), notifier signatures match the Notifier interface. Claude-Session: https://claude.ai/code/session_01Wsno14cxE49MstXFs9G5KTRestricts which email domains an organization's members may have. When a policy is configured, a user can only be added to the org (via any team) if their primary email matches one of the allowed domain globs. Enforced at the single membership choke point services/org.AddTeamMember, which every add path (API, web, group-sync) funnels through — so one check covers them all. On violation it returns a typed ErrEmailDomainNotAllowed; the API team-add handler maps it to 422. - models/git/org_email_domain.go: OrgEmailDomainPolicy model + EmailAllowed (domain glob match) + OrgEmailDomainAllowed + typed error + CRUD. Migration 366. - API: GET/PATCH/DELETE /orgs/{org}/email_domain_policy. - Enforcement in services/org/team.go; 422 mapping in routers/api/v1/org/team.go. An empty policy imposes no restriction. This is the one bounded piece of the "access/security" tier; org 2FA-required and IP allowlists were deliberately NOT built here — they are cross-cutting enforcement (auth gating / request middleware) that needs a compiler + tests, not a blind stacked PR. Stacked on #731/#730/#729/#728 for migration ordering (this = 366). Swagger omitted. Note: no Go toolchain available locally, so not compiled/gofmt'd/tested here. Hand-verified: gofmt (tabs, no blank-in-block), imports (git_model added to the api team handler, gci order), typed-error detection, migration contiguous (366). Claude-Session: https://claude.ai/code/session_01Wsno14cxE49MstXFs9G5KTAnnotate the four previously undocumented org-governance API handlers (tag_protection, push_policy, repo_defaults, email_domain) with swagger:operation blocks, and register the swagger:response models the branch_protection operations already referenced. Register the org option DTOs in the parameterBodies hack so their definitions are emitted. Also fix pre-existing spec-generation blockers surfaced once the spec became regenerable: a stray comment glued to the repoUpdateManifest swagger block (broke YAML parsing), missing owner/repo path params on the manifest operations, a Manifest response registration, and missing definitions for EditAccessTokenOption, the IssueBulk* options, and the Issue{Priority,Status,Type}Def types. Regenerated v1_json.tmpl and v1_openapi3_json.tmpl; spec now validates cleanly against Swagger 2.0. Claude-Session: https://claude.ai/code/session_01Wsno14cxE49MstXFs9G5KTValidation update (2026-07-05) — the caveats in the original description are now resolved
The description above listed two open items before merging to
main. Both are now closed:1. OpenAPI / swagger — ✅ done (#739, merged to dev). All five org-governance API groups are now fully annotated (14 operations) with registered
swagger:responsemodels, andtemplates/swagger/v1_json.tmpl+v1_openapi3_json.tmplwere regenerated. Also fixed pre-existing spec-generation blockers (a stray comment inmanifest.go, dangling$refs inoptions.go) that had left the spec un-regenerable.swagger validate→ valid vs Swagger 2.0.2. Definitive build/runtime validation — ✅ done (local + live dev deploy).
go build ./...clean andgofmt -lclean on the full integrated tree (onlytests/integration, pre-existing-broken, excluded). Also fixed a pre-existing fork-wide compile break whereapi.gocalled the renamedHasOrgOrUserVisible(#735).custom/deploy-dev.yml, run 33608 attempt 2): image built → container recreated → migrations 362–366 applied → health check + dev APIhealthzpassed. Getting there also required two deploy-workflow fixes: #737 (tag var-expansion) and #740 (container-name conflict on recreate).This branch now also carries README + CHANGELOG updates and the regenerated spec (diff grew to ~49 files as a result).
Remaining (non-blocking, tracked in #738): MCP tools for the new org endpoints (B), repo-facing read views for push-policy/repo-defaults (C), and a small race-hardening of the dev deploy (a remote
flock, sincecancel-in-progressdoesn't kill already-launched remote SSH commands — two rapid dev merges raced on attempt 1).Merging this cuts the stable org-governance release to
main.https://claude.ai/code/session_01Wsno14cxE49MstXFs9G5KT
Code-review findings on the org-governance release: - Fail closed on org-rule lookup error: getFirstMatchProtectedBranchRule swallowed FindOrgBranchRuleForBranch errors (returned nil,nil), silently dropping the org floor and falling back to the repo rule on a transient DB error. Propagate the error so the org rule stays enforced. - Stop the org rule locking out deploy-key and Actions-bot pushes: OrgProtectedBranch is team-only, so mergeMostRestrictive was ANDing the repo's WhitelistDeployKeys / WhitelistActionsUser (and the force-push, delete and merge counterparts) against the org side's always-false zero value, blocking every deploy-key and Actions push in any org with a matching branch rule. Carry those org-unmanaged fields through from the repo rule unchanged. - Org push-policy max-file-size now inspects only the pushed delta (diff-tree + cat-file --batch-check) instead of the full tip tree via ls-tree, so a pre-existing oversized file can no longer permanently block unrelated pushes. New branches (no base commit) still scan the full tree. Dev deploy targeting: - deploy-dev.yml drove the dev container image via `sed` on the SHARED compose file, but the pattern matched the *prod* service line (container_name: mokogitea) — leaving the dev service pinned to a stale image (so every "green" deploy recreated old code) while corrupting the prod image pin. Drive the dev service image from ${MOKOGITEA_DEV_TAG} instead; the env-var only affects the dev service. Claude-Session: https://claude.ai/code/session_01Wsno14cxE49MstXFs9G5KTThe branch-protection delete feature (#696/#728) added a second "repo.settings.event_delete" entry ("Branch Deletion") to locale_en-US.json, reusing the existing webhook-event key (value "Delete"). The old JSON decoder silently kept the last value; Go 1.26's jsonv2 decoder rejects duplicate object keys, so InitLocales fails ("duplicate object member name repo.settings.event_delete") and the server crash-loops at startup. Like the code-scanner regexp panic, this only surfaces on a fresh boot, which is why it shipped unnoticed. Give the branch-protection section header its own key "repo.settings.protect_branch_deletion" and point protected_branch.tmpl at it, so the webhook "Delete" label and the branch-protection "Branch Deletion" header both render correctly and the JSON has no duplicate. Verified: no duplicate keys remain in any options/locale/*.json. Claude-Session: https://claude.ai/code/session_01Wsno14cxE49MstXFs9G5KTValidation update #2 (2026-07-05) — dev now boots the real code end-to-end + this release un-breaks
mainThe first dev deploys were a false green: the workflow's
sedtargeted the wrong service in the shared compose file, somokogitea-devkept recreating from a stale June-23 image and never ran this code. Fixing the deploy targeting (#741 + host compose edits) made it finally deploy the current image — which then exposed a chain of latent startup crashes that CI/build/vet never catch because they only fire atinit()/boot:services/security/code_scanner.goused an RE2-incompatible negative lookahead(?!…)inregexp.MustCompile→ panic at package init (from #552). Fixed in #742 (merged to dev) + regression test.locale_en-US.jsonhad a duplicaterepo.settings.event_deletekey (from #696/#728) → Go 1.26 jsonv2 rejects duplicate keys →InitLocalesfatal. Fixed in #743 (merged to dev); scanned all tracked + non-tracked JSON, no others.Now verified genuinely healthy:
ORM engine initialization successful!(all migrations incl. 362–366), indexers up, zero panic/fatal, still running at timeout.mokogitea-devrunningstable-236-g3efbab985b-dev, status=running, health=healthy, restarts=0; external/api/v1/version→ 200 (new commitg3efbab985b),/api/healthz→ 200pass.Impact on this PR:
devnow also contains #742 + #743, so merging #733 carries those boot fixes tomainas part of the release. That matters becausemaincurrently has the same two crashes (via #552 and #696/#728) and is undeployable from a fresh build — production only survives on an older pre-#552 image. This release both ships org-governance and makesmainbootable again.Net: #733 is validated at the code, build, migration, and live-boot levels. Ready to merge when you are.
https://claude.ai/code/session_01Wsno14cxE49MstXFs9G5KT
Wiki reminder: docs are wiki-first -- if this PR changes behavior, usage, config, or standards, please update the repo wiki before/after merge. (non-blocking)
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.