Two related additions:
1. Branch deletion as an org-level ability. OrgProtectedBranch gained
CanDelete / EnableDeleteAllowlist / DeleteAllowlistTeamIDs (migration 362),
ToProtectedBranch maps them, and the API (create/edit/response DTOs +
handlers) exposes enable_delete / enable_delete_allowlist /
delete_allowlist_teams. The layering merge already combined delete fields, so
org delete-protection now enforces once ToProtectedBranch populates them.
2. The repo Branch Protection view now renders each inherited org rule as an
expandable detail (direct push, force-push, branch deletion, merge, required
approvals, status checks, protected files) with team names resolved, instead
of three headline badges. Still read-only.
Note: no Go toolchain available locally, so not compiled/gofmt'd/tested here.
Verified by hand: struct-field gofmt alignment, template block nesting balances,
every .Rule field exists on OrgProtectedBranch, and all locale keys referenced
in the template are defined.
Claude-Session: https://claude.ai/code/session_01Wsno14cxE49MstXFs9G5KT
The org "floor" is enforced implicitly at the choke point, so a repo admin
couldn't see which org-level rules apply to their repo. Surface them in the
repo's Branch Protection settings page (read-only), the way GitHub shows
organization rulesets in a repository.
- ProtectedBranchRules handler: when the owner is an org, load
FindOrgProtectedBranchRules and expose them as OrgProtectedBranches.
- branches.tmpl: new read-only "Organization Branch Protection" section listing
each org rule with an "Organization" badge, a lock/read-only marker, and
compact indicators (required approvals, signed commits, status checks). No
edit/delete controls — these are managed at the org level.
- en-US locale strings.
Note: no Go toolchain available locally, so not compiled/gofmt'd/tested here.
Claude-Session: https://claude.ai/code/session_01Wsno14cxE49MstXFs9G5KT
Org-level branch protection was already consulted at the single enforcement
choke point `GetFirstMatchProtectedBranchRule`, but only as a FALLBACK: if any
repo-level rule matched the branch, the org rule was ignored entirely. That let
a repo define a looser rule for a pattern and effectively opt out of the org's
protection.
Make the choke point LAYER the two rules instead: when both an org rule and a
repo rule match a branch, return their most-restrictive (fail-closed)
combination, so the org rule is a mandatory floor a repo can only tighten.
- models/git/protected_branch_merge.go: mergeMostRestrictive + helpers. Allow
flags AND'd; gate/require/block flags OR'd; RequiredApprovals max'd; required
sets (status contexts, protected files) unioned; allow sets (whitelists,
unprotected files) intersected. A disabled allowlist means "everyone", so it
only constrains when enabled.
- models/git/protected_branch_list.go: GetFirstMatchProtectedBranchRule now
fetches both the repo rule and the org rule and merges when both match;
returns whichever exists when only one matches. Org lookup factored into
getFirstMatchOrgProtectedBranchRule.
Supersedes the materialization approach previously proposed for this issue —
the org fallback already existed, so only this one function needed to change.
Fail-closed by design: any merge edge errs toward MORE protection (over-restrict)
rather than less, so it cannot open a hole.
Note: no Go toolchain available locally, so not compiled/gofmt'd/tested here —
relying on CI to validate build, formatting, and tests.
Claude-Session: https://claude.ai/code/session_01Wsno14cxE49MstXFs9G5KT
#720: org Teams page wrote ctx.Data["OrgListTeams"] but the template iterates .Teams, so no teams rendered. Use the canonical Teams key (matches org/home.go). #721: issue type sidebar gated editing on a FieldEditFlags data key that no handler sets (always nil -> always read-only). Use HasIssuesOrPullsWritePermission like the priority field; the /custom-type endpoint is already protected by reqRepoIssuesOrPullsWriter.
The RC release workflow drives a Joomla-style updates.xml update stream. On a generic repo with no updates.xml, the Determine RC version step ran sed on a missing file and aborted under set -e (exit 2). Detect updates.xml presence and gate the update-stream steps (edit/create-release/commit) on it so the job succeeds and no-ops when there is nothing to package.
The tree carried a gitlink at mcp-mokogitea-api (mode 160000) with no .gitmodules entry, so git submodule update --init --recursive failed with exit 128 at checkout, breaking every PR build/release job. mcp-mokogitea-api is a separate repo, not a submodule; remove the gitlink from the index (keeping the local working-tree clone) and gitignore the path so it can't be re-added.
Branch policy in pr-check.yml only allowed fix/* and patch/* to target dev/rc, blocking fix/* PRs to main despite the documented policy. Allow fix/* -> main and patch/* -> main. Also guard the Detect platform step for a missing .mokogitea/manifest.xml (removed in favor of the metadata API) so it no longer aborts the Validate PR job under set -e.
LandingPageType.Mode defaults to "" (Go zero value), and the template renders the home radio as checked for an empty Mode. The initial radio fill would evaluate home.checked = ("home" === "") = false, unchecking the default on a fresh install. Skip assignment when the config value is empty so the server-rendered selection is preserved. Adds a test for the empty-value case.
The system config form JS (config.ts) only mapped checkbox, text, textarea, and datetime-local elements. The fork landing_page.tmpl uses radio inputs for the Mode field, so fillFromSystemConfig() hit unsupportedElement() and threw, aborting all JS init on the admin settings page.
Add radio handling in both directions: fill checks the option whose value matches the config value; collect returns the checked option's value and skips/nulls unchecked radios so a group resolves to exactly one value. Adds a radio-group test case.