Skip to content

Add GraphQL API for projects/groups linked to security policy project

What does this MR do and why?

This MR adds 2 new fields to ProjectsType GraphQL API: securityPolicyProjectLinkedProjects and securityPolicyProjectLinkedNamespaces. These fields are providing information about linked projects and namespaces to given project, when used as Security Policy Project.

Queries

explain 
SELECT 
  "projects"."id", 
  "projects"."name", 
  "projects"."path", 
  "projects"."description", 
  "projects"."created_at", 
  "projects"."updated_at", 
  "projects"."creator_id", 
  "projects"."namespace_id", 
  "projects"."last_activity_at", 
  "projects"."import_url", 
  "projects"."visibility_level", 
  "projects"."archived", 
  "projects"."avatar", 
  "projects"."merge_requests_template", 
  "projects"."star_count", 
  "projects"."merge_requests_rebase_enabled", 
  "projects"."import_type", 
  "projects"."import_source", 
  "projects"."approvals_before_merge", 
  "projects"."reset_approvals_on_push", 
  "projects"."merge_requests_ff_only_enabled", 
  "projects"."issues_template", 
  "projects"."mirror", 
  "projects"."mirror_last_update_at", 
  "projects"."mirror_last_successful_update_at", 
  "projects"."mirror_user_id", 
  "projects"."shared_runners_enabled", 
  "projects"."runners_token", 
  "projects"."build_allow_git_fetch", 
  "projects"."build_timeout", 
  "projects"."mirror_trigger_builds", 
  "projects"."pending_delete", 
  "projects"."public_builds", 
  "projects"."last_repository_check_failed", 
  "projects"."last_repository_check_at", 
  "projects"."only_allow_merge_if_pipeline_succeeds", 
  "projects"."has_external_issue_tracker", 
  "projects"."repository_storage", 
  "projects"."repository_read_only", 
  "projects"."request_access_enabled", 
  "projects"."has_external_wiki", 
  "projects"."ci_config_path", 
  "projects"."lfs_enabled", 
  "projects"."description_html", 
  "projects"."only_allow_merge_if_all_discussions_are_resolved", 
  "projects"."repository_size_limit", 
  "projects"."printing_merge_request_link_enabled", 
  "projects"."auto_cancel_pending_pipelines", 
  "projects"."service_desk_enabled", 
  "projects"."cached_markdown_version", 
  "projects"."delete_error", 
  "projects"."last_repository_updated_at", 
  "projects"."disable_overriding_approvers_per_merge_request", 
  "projects"."storage_version", 
  "projects"."resolve_outdated_diff_discussions", 
  "projects"."remote_mirror_available_overridden", 
  "projects"."only_mirror_protected_branches", 
  "projects"."pull_mirror_available_overridden", 
  "projects"."jobs_cache_index", 
  "projects"."external_authorization_classification_label", 
  "projects"."mirror_overwrites_diverged_branches", 
  "projects"."pages_https_only", 
  "projects"."external_webhook_token", 
  "projects"."packages_enabled", 
  "projects"."merge_requests_author_approval", 
  "projects"."pool_repository_id", 
  "projects"."runners_token_encrypted", 
  "projects"."bfg_object_map", 
  "projects"."detected_repository_languages", 
  "projects"."merge_requests_disable_committers_approval", 
  "projects"."require_password_to_approve", 
  "projects"."max_pages_size", 
  "projects"."max_artifacts_size", 
  "projects"."pull_mirror_branch_prefix", 
  "projects"."remove_source_branch_after_merge", 
  "projects"."marked_for_deletion_at", 
  "projects"."marked_for_deletion_by_user_id", 
  "projects"."autoclose_referenced_issues", 
  "projects"."suggestion_commit_message", 
  "projects"."project_namespace_id", 
  "projects"."hidden", 
  "projects"."organization_id" 
FROM 
  "projects" 
  INNER JOIN "security_orchestration_policy_configurations" ON "projects"."id" = "security_orchestration_policy_configurations"."project_id" 
WHERE 
  "security_orchestration_policy_configurations"."security_policy_management_project_id" = 52773995

https://postgres.ai/console/gitlab/gitlab-production-tunnel-pg12/sessions/25971/commands/81716

explain 
SELECT 
  "namespaces"."id", 
  "namespaces"."name", 
  "namespaces"."path", 
  "namespaces"."owner_id", 
  "namespaces"."created_at", 
  "namespaces"."updated_at", 
  "namespaces"."type", 
  "namespaces"."description", 
  "namespaces"."avatar", 
  "namespaces"."membership_lock", 
  "namespaces"."share_with_group_lock", 
  "namespaces"."visibility_level", 
  "namespaces"."request_access_enabled", 
  "namespaces"."ldap_sync_status", 
  "namespaces"."ldap_sync_error", 
  "namespaces"."ldap_sync_last_update_at", 
  "namespaces"."ldap_sync_last_successful_update_at", 
  "namespaces"."ldap_sync_last_sync_at", 
  "namespaces"."description_html", 
  "namespaces"."lfs_enabled", 
  "namespaces"."parent_id", 
  "namespaces"."shared_runners_minutes_limit", 
  "namespaces"."repository_size_limit", 
  "namespaces"."require_two_factor_authentication", 
  "namespaces"."two_factor_grace_period", 
  "namespaces"."cached_markdown_version", 
  "namespaces"."project_creation_level", 
  "namespaces"."runners_token", 
  "namespaces"."file_template_project_id", 
  "namespaces"."saml_discovery_token", 
  "namespaces"."runners_token_encrypted", 
  "namespaces"."custom_project_templates_group_id", 
  "namespaces"."auto_devops_enabled", 
  "namespaces"."extra_shared_runners_minutes_limit", 
  "namespaces"."last_ci_minutes_notification_at", 
  "namespaces"."last_ci_minutes_usage_notification_level", 
  "namespaces"."subgroup_creation_level", 
  "namespaces"."emails_disabled", 
  "namespaces"."max_pages_size", 
  "namespaces"."max_artifacts_size", 
  "namespaces"."mentions_disabled", 
  "namespaces"."default_branch_protection", 
  "namespaces"."max_personal_access_token_lifetime", 
  "namespaces"."push_rule_id", 
  "namespaces"."shared_runners_enabled", 
  "namespaces"."allow_descendants_override_disabled_shared_runners", 
  "namespaces"."traversal_ids", 
  "namespaces"."organization_id" 
FROM 
  "namespaces" 
  INNER JOIN "security_orchestration_policy_configurations" ON "namespaces"."id" = "security_orchestration_policy_configurations"."namespace_id" 
WHERE 
  "security_orchestration_policy_configurations"."security_policy_management_project_id" = 54175436

https://postgres.ai/console/gitlab/gitlab-production-tunnel-pg12/sessions/25971/commands/81717

MR acceptance checklist

Please evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

GraphQL

Request

query {
  project(fullPath: "haven/omega/omega-security-policy-project") {
    securityPolicyProjectLinkedProjects {
      nodes {
        id
        name
      }
    }
    
    securityPolicyProjectLinkedNamespaces {
      nodes {
        id
        name
      }
    }
  }
}

Response

{
  "data": {
    "project": {
      "securityPolicyProjectLinkedProjects": {
        "nodes": [
          {
            "id": "gid://gitlab/Project/96",
            "name": "just a regular project"
          }
        ]
      },
      "securityPolicyProjectLinkedNamespaces": {
        "nodes": [
          {
            "id": "gid://gitlab/Group/182",
            "name": "omega"
          }
        ]
      }
    }
  }
}

How to set up and validate locally

  1. Create a new group and subgroup.
  2. Create a new project in the top group.
  3. Create a new policy for the project and merge the created MR.
  4. Go to the subgroup, in Secure -> Policies, click on Edit Security Policy Project, select Security Policy Project created in point 3.
  5. Go to GraphQL Explorer (/-/graphql-explorer) and use query provided above for selected Security Policy Project and verify that you see both linked project and namespace.

Related to #432513 (closed)

Merge request reports