Draft: Allow public container images to be viewed at group level
What does this MR do and why?
Fixes #390311: the group-level Container Registry page (e.g. /groups/<group>/-/container_registries) was returning 404 for non-members and anonymous users of public groups, even when projects in the group have public container images.
Root cause
config/authz/roles/public_anonymous.yml grants read_container_image under the project: section but not under the group: section. So can?(user, :read_container_image, group) failed for non-members, causing the controller to render 404 and the sidebar item to be hidden.
Changes
1. config/authz/roles/public_anonymous.yml
Added read_container_image to the group: raw_permissions list (alphabetically sorted). This grants the permission to anonymous users and, via inheritance, to public_authenticated (logged-in non-members) on public groups.
2. app/models/container_repository.rb
Added a new scope for_group_and_its_subgroups_visible_to(group, user) that filters repositories to only those from projects visible to the given user, respecting:
- Project visibility (public/internal/private via
Project.public_or_visible_to_user) - Container registry feature access level (via
ProjectFeature.with_feature_available_for_user)
The existing for_group_and_its_subgroups scope is unchanged (used by Group#has_container_repository_including_subgroups? for admin checks that must see all repos).
3. app/finders/container_repositories_finder.rb
Updated group_repositories to use the new visibility-aware scope, ensuring private/internal project images are never exposed to users who cannot see those projects.
Security
- Anonymous users see only repositories from public projects with container registry set to ENABLED or PUBLIC
- Logged-in non-members see repositories from public and internal projects with accessible registry
- Private project images are never exposed to non-members
- Private group behavior is unchanged (404 for non-members)
Group#has_container_repository_including_subgroups?(used for transfer/deletion/rename checks) is unaffected
SQL query for the new scope (for database review)
SELECT container_repositories.*
FROM container_repositories
INNER JOIN (
SELECT projects.id
FROM projects
INNER JOIN namespaces ON namespaces.id = projects.namespace_id
INNER JOIN project_features ON project_features.project_id = projects.id
WHERE namespaces.id IN (
SELECT id FROM namespaces WHERE traversal_ids @> ARRAY[<group_id>]
)
AND projects.visibility_level IN (20) -- public only (for anonymous)
AND (
project_features.container_registry_access_level IN (20, 30) -- ENABLED, PUBLIC
OR project_features.container_registry_access_level IS NULL
)
) projects ON projects.id = container_repositories.project_idThe existing index index_project_features_on_project_id_include_container_registry (btree on project_id INCLUDE container_registry_access_level) supports this query efficiently.
References
- Issue: #390311
Screenshots or screen recordings
N/A (backend-only change)
| Before | After |
|---|---|
| Group container registry page returns 404 for anonymous/non-member on public group | Returns 200 and shows only images from visible projects |
How to set up and validate locally
- Create a public group with a public project that has container images
- Visit
/groups/<group>/-/container_registrieswhile logged out - Before: 404. After: 200 showing public project images
- Verify private project images in the same group are not shown
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.