Scope policy scope projects and groups to the policy's hierarchy
What does this MR do?
PolicyScopeFetcher#scoped_projects and #scoped_groups resolved scope.projects.including/excluding and scope.groups.including/excluding by bare ID against Project/Group, unscoped — while the sibling compliance_frameworks and security_attributes resolvers in the same class already scope to the policy's root ancestor. A policy could reference a project or group from a different organization by ID and have it resolved and returned (e.g. over GraphQL, disclosing its existence and public data).
This scopes both to the policy's root ancestor (root_ancestor.all_projects / root_ancestor.self_and_descendants), consistent with the other resolvers in the class. The self-managed instance-level policy fallback (no container) is preserved unchanged, matching the existing compliance_frameworks behavior for that case — see the note below.
Note on scope: a related, lower-severity gap in the same file — compliance_frameworks falls back to an instance-wide match on self-managed when there's no container — is not fixed here. Removing that fallback would change real behavior for self-managed instance-level policies (no framework scoping at all when there's no namespace context), which is a product decision, not a drop-in fix. Flagging it as a separate follow-up rather than bundling it in.
Production impact today: none. GitLab.com is single-organization, so this closes a gap that only becomes exploitable once multi-organization/Cells ships.
References
Relates to https://gitlab.com/gitlab-com/gl-infra/tenant-scale/organizations/organizations-feature-parity/-/work_items/102 (additional finding beyond the original audit: policy scope projects/groups resolution)
How to test
bundle exec rspec ee/spec/lib/security/security_orchestration_policies/policy_scope_fetcher_spec.rb