Skip to content

Expose `user_access` Project/Group Authorizations of agents

Shinya Maeda requested to merge expose-agent-user-access-authorizations into master

NOTE: This MR is built on top of Optimize AuthorizeProxyUserService with user_ac... (!116905 - merged).

What does this MR do and why?

This MR exposes the persisted user_access authorizations for Show shared agents in deployment projects (#395498 - closed).

A few notes:

Screenshots or screen recordings

Query:

query {
  project(fullPath: "root/agent-ci-test") {
    name
    userAccessAuthorizedAgents {
      nodes {
        agent {
          id
          name
          project {
            name
          }
        }
        config
      }
    }
  }
}

Response:

{
  "data": {
    "project": {
      "name": "agent-ci-test",
      "userAccessAuthorizedAgents": {
        "nodes": [
          {
            "agent": {
              "id": "gid://gitlab/Clusters::Agent/37",
              "name": "production",
              "project": {
                "name": "agent-ci-test"
              }
            },
            "config": {}
          },
          {
            "agent": {
              "id": "gid://gitlab/Clusters::Agent/43",
              "name": "production",
              "project": {
                "name": "agent-ci-test-2"
              }
            },
            "config": {}
          }
        ]
      }
    }
  }
}

Database Query for user_access_authorized_for?

NOTE: This feature is not exposed for end-users yet therefore there are no production records that match the following queries. We'll evaluate the query performance after the feature flag has been enabled.

SELECT
    agent_user_access_project_authorizations.*,
    project_authorizations.access_level AS access_level
FROM
    "agent_user_access_project_authorizations"
    INNER JOIN project_authorizations ON project_authorizations.project_id = agent_user_access_project_authorizations.project_id
WHERE
    "project_authorizations"."user_id" = 758045
    AND "project_authorizations"."access_level" >= 30
    AND "agent_user_access_project_authorizations"."agent_id" = 57145
LIMIT
    1

query plan

WITH "groups_with_direct_membership" AS MATERIALIZED (
    SELECT
        namespaces.id AS id,
        members.access_level AS access_level
    FROM
        "namespaces"
        INNER JOIN members ON members.source_id = namespaces.id
        AND members.source_type = 'Namespace'
    WHERE
        "namespaces"."type" = 'Group'
        AND "members"."user_id" = 758045
        AND "members"."access_level" >= 30
),
"all_groups_with_membership" AS MATERIALIZED (
    SELECT
        namespaces.id AS id,
        namespaces.traversal_ids AS traversal_ids,
        groups_with_direct_membership.access_level AS access_level
    FROM
        "namespaces"
        INNER JOIN groups_with_direct_membership ON namespaces.traversal_ids @> ARRAY [groups_with_direct_membership.id]
    WHERE
        "namespaces"."type" = 'Group'
)
SELECT
    DISTINCT ON (id) agent_user_access_group_authorizations.*,
    all_groups_with_membership.access_level AS access_level
FROM
    "agent_user_access_group_authorizations"
    INNER JOIN all_groups_with_membership ON all_groups_with_membership.id = agent_user_access_group_authorizations.group_id
WHERE
    "agent_user_access_group_authorizations"."agent_id" = 57145
ORDER BY
    id,
    access_level DESC
LIMIT
    1

query plan

Database Query for UserAccessResolver

SELECT
    agent_user_access_project_authorizations.*,
    project_authorizations.access_level AS access_level
FROM
    "agent_user_access_project_authorizations"
    INNER JOIN project_authorizations ON project_authorizations.project_id = agent_user_access_project_authorizations.project_id
    INNER JOIN "cluster_agents" ON "cluster_agents"."id" = "agent_user_access_project_authorizations"."agent_id"
    INNER JOIN "projects" ON "projects"."id" = "cluster_agents"."project_id"
WHERE
    "project_authorizations"."user_id" = 758045
    AND "project_authorizations"."access_level" >= 30
    AND "agent_user_access_project_authorizations"."project_id" = 278964

query plan

WITH "groups_with_direct_membership" AS MATERIALIZED (
    SELECT
        namespaces.id AS id,
        members.access_level AS access_level
    FROM
        "namespaces"
        INNER JOIN members ON members.source_id = namespaces.id
        AND members.source_type = 'Namespace'
    WHERE
        "namespaces"."type" = 'Group'
        AND "members"."user_id" = 758045
        AND "members"."access_level" >= 30
),
"all_groups_with_membership" AS MATERIALIZED (
    SELECT
        namespaces.id AS id,
        namespaces.traversal_ids AS traversal_ids,
        groups_with_direct_membership.access_level AS access_level
    FROM
        "namespaces"
        INNER JOIN groups_with_direct_membership ON namespaces.traversal_ids @> ARRAY [groups_with_direct_membership.id]
    WHERE
        "namespaces"."type" = 'Group'
)
SELECT
    DISTINCT ON (id) agent_user_access_group_authorizations.*,
    all_groups_with_membership.access_level AS access_level
FROM
    "agent_user_access_group_authorizations"
    INNER JOIN all_groups_with_membership ON all_groups_with_membership.id = agent_user_access_group_authorizations.group_id
    INNER JOIN "cluster_agents" ON "cluster_agents"."id" = "agent_user_access_group_authorizations"."agent_id"
    INNER JOIN "projects" ON "projects"."id" = "cluster_agents"."project_id"
WHERE
    (
        all_groups_with_membership.traversal_ids @> ARRAY [9970]
    )
ORDER BY
    id,
    access_level DESC

query plan

MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Shinya Maeda

Merge request reports