Skip to content

Organizations with limited visibility hide every tab except Repositories for non-members #38870

Description

@dianaStr7

Gitea Version

1.27.0

What happened?

An organization set to Limited ("Visible only to authenticated users") shows a signed-in non-member only the Repositories tab. Packages, Code and Projects are gone from the org menu. Packages still loads if the URL is entered directly, despite the hidden tab; Code and Projects return 404. The same organization set to Public shows all of these tabs to everyone, including anonymous visitors.

Expected behaviour: limited should show the same tabs as public, with the audience narrowed to authenticated users.

Root cause

Organization.UnitPermission() in models/organization/org.go:

if doer != nil {
	teams, _ := GetUserOrgTeams(ctx, org.ID, doer.ID)
	if len(teams) > 0 {
		return teams.UnitMaxAccess(unitType)
	}
}

if org.Visibility.IsPublic() {
	return perm.AccessModeRead
}
return perm.AccessModeNone

A signed-in non-member has no teams in the org, so it skips the first block. IsPublic() is a strict == VisibleTypePublic, so limited falls through to AccessModeNone.

That one check causes both symptoms:

Hidden tabsservices/context/org.go:

ctx.Data["CanReadProjects"] = ctx.Org.CanReadUnit(ctx, unit.TypeProjects)
ctx.Data["CanReadPackages"] = ctx.Org.CanReadUnit(ctx, unit.TypePackages)
ctx.Data["CanReadCode"]     = ctx.Org.CanReadUnit(ctx, unit.TypeCode)

CanReadUnit() just wraps UnitPermission(), and templates/org/menu.tmpl shows the tabs only {{if .CanReadPackages}} etc. All three are false, so all three tabs vanish. Repositories stays because it uses repo-level visibility, not this function.

404sreqUnitAccess in routers/web/web.go, used on /-/code and /-/projects:

if ctx.Org.Organization.UnitPermission(ctx, ctx.Doer, unitType) < accessMode {
	ctx.NotFound(nil)
}

Packages still loads, because that route uses a different guard, determineAccessMode() in services/context/package.go, which handles limited correctly:

if accessMode == perm.AccessModeNone && organization.HasOrgOrUserVisible(ctx, pkgOwner, doer) {
	accessMode = perm.AccessModeRead
}

So the page is served, but the tab linking to it is hidden. UnitPermission() is the only place that checks IsPublic() instead of HasOrgOrUserVisible().

How are you running Gitea?

Official gitea/gitea Docker image running on Kubernetes managed by Rancher, with PostgreSQL as the database.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions