Update Authz::RedactionService with explicit ability and new resource types

What does this MR do and why?

Updates Authz::RedactionService to accept explicit ability names and adds all resource types needed for Knowledge Graph indexing.

See the larger implementation notes: $5936072

Decision from sync with Ian and Jay

In a sync with @jayswain and @imand3r, we decided to always pass in the ability name. If no ability is provided, access is denied (fail-closed). This replaces the visible_result? pattern that derived the ability from to_ability_name.

What changed

  • Each resource type config now accepts an ability field. The ability is required -- if omitted, the resource is denied (fail-closed).
  • Resource type keys are now singular to match the Ruby model underscore convention ('issues' -> 'issue', 'merge_requests' -> 'merge_request').
  • Input format is { 'type' => { 'ids' => [...], 'ability' => '...' } }
  • New CE types: user, group
  • New EE types: ci_pipeline, ci_stage, ci_build, label, note, security_scan, security_finding, vulnerability_scanner, vulnerability_occurrence, vulnerability_identifier

Why explicit ability?

The old visible_result? pattern derived the ability from resource.to_ability_name, which only supported read_* checks. With explicit ability names:

  • The Knowledge Graph server controls which ability to check per resource type
  • Different abilities can be checked for the same resource type (e.g. read_code for projects that contain file/directory resources)
  • If the ability is missing or empty, access is denied -- always fail-closed

Resource type keys

Resource type keys are now singular and match the Ruby model underscore convention:

Ruby Model Key
Issue issue
MergeRequest merge_request
Project project
Milestone milestone
Snippet snippet
User user
Group group
Epic epic
Vulnerability vulnerability
Ci::Pipeline ci_pipeline
Ci::Stage ci_stage
Ci::Build ci_build
Label label
Note note
Security::Scan security_scan
Security::Finding security_finding
Vulnerabilities::Scanner vulnerability_scanner
Vulnerabilities::Finding vulnerability_occurrence
Vulnerabilities::Identifier vulnerability_identifier

References

How to set up and validate locally

1. Basic redaction check

Open a Rails console and test with accessible vs inaccessible resources:

user = User.where(admin: false).first
public_project = Project.find_by(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
private_project = Project.where(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
  .where.not(id: user.authorized_projects.select(:id)).first

service = Authz::RedactionService.new(
  user: user,
  resources_by_type: {
    'project' => {
      'ids' => [public_project.id, private_project.id],
      'ability' => 'read_project'
    }
  },
  source: 'console_test'
)
result = service.execute
# => { 'project' => { <public_id> => true, <private_id> => false } }

2. Verify fail-closed behavior

When no ability is provided, all resources are denied:

service = Authz::RedactionService.new(
  user: user,
  resources_by_type: {
    'project' => { 'ids' => [public_project.id, private_project.id] }
  },
  source: 'console_test'
)
result = service.execute
# => { 'project' => { <public_id> => false, <private_id> => false } }
# Both denied because no ability was specified

3. Verify issue redaction

user = User.where(admin: false).first

accessible_issue = Issue.joins(:project)
  .where(projects: { visibility_level: Gitlab::VisibilityLevel::PUBLIC })
  .where(confidential: false).first

inaccessible_issue = Issue.joins(:project)
  .where(projects: { visibility_level: Gitlab::VisibilityLevel::PRIVATE })
  .where.not(project_id: user.authorized_projects.select(:id)).first

service = Authz::RedactionService.new(
  user: user,
  resources_by_type: {
    'issue' => {
      'ids' => [accessible_issue.id, inaccessible_issue.id],
      'ability' => 'read_issue'
    }
  },
  source: 'console_test'
)
result = service.execute
# => { 'issue' => { <accessible_id> => true, <inaccessible_id> => false } }

4. Verify supported types

Authz::RedactionService.supported_types.sort
# => ["ci_build", "ci_pipeline", "ci_stage", "epic", "group", "issue",
#     "label", "merge_request", "milestone", "note", "project",
#     "security_finding", "security_scan", "snippet", "user",
#     "vulnerability", "vulnerability_identifier",
#     "vulnerability_occurrence", "vulnerability_scanner"]

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.

Edited by Michael Angelo Rivera

Merge request reports

Loading