Commit dc5b035f authored by Robert May's avatar Robert May

Merge branch 'agent-token-status-filter' into 'master'

Enable filtering agent tokens by status

See merge request gitlab-org/gitlab!77735
parents ea815d82 caab6575
...@@ -9,10 +9,17 @@ module Resolvers ...@@ -9,10 +9,17 @@ module Resolvers
delegate :project, to: :agent delegate :project, to: :agent
argument :status, Types::Clusters::AgentTokenStatusEnum,
required: false,
description: 'Status of the token.'
def resolve(**args) def resolve(**args)
return ::Clusters::AgentToken.none unless can_read_agent_tokens? return ::Clusters::AgentToken.none unless can_read_agent_tokens?
agent.last_used_agent_tokens tokens = agent.last_used_agent_tokens
tokens = tokens.with_status(args[:status]) if args[:status].present?
tokens
end end
private private
......
# frozen_string_literal: true
module Types
module Clusters
class AgentTokenStatusEnum < BaseEnum
graphql_name 'AgentTokenStatus'
description 'Agent token statuses'
::Clusters::AgentToken.statuses.keys.each do |status|
value status.upcase, value: status, description: "#{status.titleize} agent token."
end
end
end
end
...@@ -45,7 +45,7 @@ module Types ...@@ -45,7 +45,7 @@ module Types
description: 'Name given to the token.' description: 'Name given to the token.'
field :status, field :status,
GraphQL::Types::String, Types::Clusters::AgentTokenStatusEnum,
null: true, null: true,
description: 'Current status of the token.' description: 'Current status of the token.'
......
...@@ -22,6 +22,7 @@ module Clusters ...@@ -22,6 +22,7 @@ module Clusters
validates :name, presence: true, length: { maximum: 255 } validates :name, presence: true, length: { maximum: 255 }
scope :order_last_used_at_desc, -> { order(::Gitlab::Database.nulls_last_order('last_used_at', 'DESC')) } scope :order_last_used_at_desc, -> { order(::Gitlab::Database.nulls_last_order('last_used_at', 'DESC')) }
scope :with_status, -> (status) { where(status: status) }
enum status: { enum status: {
active: 0, active: 0,
......
...@@ -9027,10 +9027,27 @@ GitLab CI/CD configuration template. ...@@ -9027,10 +9027,27 @@ GitLab CI/CD configuration template.
| <a id="clusteragentid"></a>`id` | [`ID!`](#id) | ID of the cluster agent. | | <a id="clusteragentid"></a>`id` | [`ID!`](#id) | ID of the cluster agent. |
| <a id="clusteragentname"></a>`name` | [`String`](#string) | Name of the cluster agent. | | <a id="clusteragentname"></a>`name` | [`String`](#string) | Name of the cluster agent. |
| <a id="clusteragentproject"></a>`project` | [`Project`](#project) | Project this cluster agent is associated with. | | <a id="clusteragentproject"></a>`project` | [`Project`](#project) | Project this cluster agent is associated with. |
| <a id="clusteragenttokens"></a>`tokens` | [`ClusterAgentTokenConnection`](#clusteragenttokenconnection) | Tokens associated with the cluster agent. (see [Connections](#connections)) |
| <a id="clusteragentupdatedat"></a>`updatedAt` | [`Time`](#time) | Timestamp the cluster agent was updated. | | <a id="clusteragentupdatedat"></a>`updatedAt` | [`Time`](#time) | Timestamp the cluster agent was updated. |
| <a id="clusteragentwebpath"></a>`webPath` | [`String`](#string) | Web path of the cluster agent. | | <a id="clusteragentwebpath"></a>`webPath` | [`String`](#string) | Web path of the cluster agent. |
#### Fields with arguments
##### `ClusterAgent.tokens`
Tokens associated with the cluster agent.
Returns [`ClusterAgentTokenConnection`](#clusteragenttokenconnection).
This field returns a [connection](#connections). It accepts the
four standard [pagination arguments](#connection-pagination-arguments):
`before: String`, `after: String`, `first: Int`, `last: Int`.
###### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="clusteragenttokensstatus"></a>`status` | [`AgentTokenStatus`](#agenttokenstatus) | Status of the token. |
### `ClusterAgentActivityEvent` ### `ClusterAgentActivityEvent`
#### Fields #### Fields
...@@ -9056,7 +9073,7 @@ GitLab CI/CD configuration template. ...@@ -9056,7 +9073,7 @@ GitLab CI/CD configuration template.
| <a id="clusteragenttokenid"></a>`id` | [`ClustersAgentTokenID!`](#clustersagenttokenid) | Global ID of the token. | | <a id="clusteragenttokenid"></a>`id` | [`ClustersAgentTokenID!`](#clustersagenttokenid) | Global ID of the token. |
| <a id="clusteragenttokenlastusedat"></a>`lastUsedAt` | [`Time`](#time) | Timestamp the token was last used. | | <a id="clusteragenttokenlastusedat"></a>`lastUsedAt` | [`Time`](#time) | Timestamp the token was last used. |
| <a id="clusteragenttokenname"></a>`name` | [`String`](#string) | Name given to the token. | | <a id="clusteragenttokenname"></a>`name` | [`String`](#string) | Name given to the token. |
| <a id="clusteragenttokenstatus"></a>`status` | [`String`](#string) | Current status of the token. | | <a id="clusteragenttokenstatus"></a>`status` | [`AgentTokenStatus`](#agenttokenstatus) | Current status of the token. |
### `CodeCoverageActivity` ### `CodeCoverageActivity`
...@@ -16150,6 +16167,15 @@ Access level to a resource. ...@@ -16150,6 +16167,15 @@ Access level to a resource.
| <a id="accesslevelenumowner"></a>`OWNER` | Owner access. | | <a id="accesslevelenumowner"></a>`OWNER` | Owner access. |
| <a id="accesslevelenumreporter"></a>`REPORTER` | Reporter access. | | <a id="accesslevelenumreporter"></a>`REPORTER` | Reporter access. |
### `AgentTokenStatus`
Agent token statuses.
| Value | Description |
| ----- | ----------- |
| <a id="agenttokenstatusactive"></a>`ACTIVE` | Active agent token. |
| <a id="agenttokenstatusrevoked"></a>`REVOKED` | Revoked agent token. |
### `AlertManagementAlertSort` ### `AlertManagementAlertSort`
Values for sorting alerts. Values for sorting alerts.
...@@ -7,5 +7,9 @@ FactoryBot.define do ...@@ -7,5 +7,9 @@ FactoryBot.define do
token_encrypted { Gitlab::CryptoHelper.aes256_gcm_encrypt(SecureRandom.hex(50)) } token_encrypted { Gitlab::CryptoHelper.aes256_gcm_encrypt(SecureRandom.hex(50)) }
sequence(:name) { |n| "agent-token-#{n}" } sequence(:name) { |n| "agent-token-#{n}" }
trait :revoked do
status { :revoked }
end
end end
end end
...@@ -7,6 +7,7 @@ RSpec.describe Resolvers::Clusters::AgentTokensResolver do ...@@ -7,6 +7,7 @@ RSpec.describe Resolvers::Clusters::AgentTokensResolver do
it { expect(described_class.type).to eq(Types::Clusters::AgentTokenType) } it { expect(described_class.type).to eq(Types::Clusters::AgentTokenType) }
it { expect(described_class.null).to be_truthy } it { expect(described_class.null).to be_truthy }
it { expect(described_class.arguments.keys).to contain_exactly('status') }
describe '#resolve' do describe '#resolve' do
let(:agent) { create(:cluster_agent) } let(:agent) { create(:cluster_agent) }
...@@ -23,6 +24,14 @@ RSpec.describe Resolvers::Clusters::AgentTokensResolver do ...@@ -23,6 +24,14 @@ RSpec.describe Resolvers::Clusters::AgentTokensResolver do
expect(subject).to eq([matching_token2, matching_token1]) expect(subject).to eq([matching_token2, matching_token1])
end end
context 'token status is specified' do
let!(:revoked_token) { create(:cluster_agent_token, :revoked, agent: agent) }
subject { resolve(described_class, obj: agent, ctx: ctx, args: { status: 'revoked' }) }
it { is_expected.to contain_exactly(revoked_token) }
end
context 'user does not have permission' do context 'user does not have permission' do
let(:user) { create(:user, developer_projects: [agent.project]) } let(:user) { create(:user, developer_projects: [agent.project]) }
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Types::Clusters::AgentTokenStatusEnum do
it { expect(described_class.graphql_name).to eq('AgentTokenStatus') }
it { expect(described_class.values.keys).to match_array(Clusters::AgentToken.statuses.keys.map(&:upcase)) }
end
...@@ -13,15 +13,25 @@ RSpec.describe Clusters::AgentToken do ...@@ -13,15 +13,25 @@ RSpec.describe Clusters::AgentToken do
describe 'scopes' do describe 'scopes' do
describe '.order_last_used_at_desc' do describe '.order_last_used_at_desc' do
let_it_be(:token_1) { create(:cluster_agent_token, last_used_at: 7.days.ago) } let_it_be(:agent) { create(:cluster_agent) }
let_it_be(:token_2) { create(:cluster_agent_token, last_used_at: nil) } let_it_be(:token_1) { create(:cluster_agent_token, agent: agent, last_used_at: 7.days.ago) }
let_it_be(:token_3) { create(:cluster_agent_token, last_used_at: 2.days.ago) } let_it_be(:token_2) { create(:cluster_agent_token, agent: agent, last_used_at: nil) }
let_it_be(:token_3) { create(:cluster_agent_token, agent: agent, last_used_at: 2.days.ago) }
it 'sorts by last_used_at descending, with null values at last' do it 'sorts by last_used_at descending, with null values at last' do
expect(described_class.order_last_used_at_desc) expect(described_class.order_last_used_at_desc)
.to eq([token_3, token_1, token_2]) .to eq([token_3, token_1, token_2])
end end
end end
describe '.with_status' do
let!(:active_token) { create(:cluster_agent_token) }
let!(:revoked_token) { create(:cluster_agent_token, :revoked) }
subject { described_class.with_status(:active) }
it { is_expected.to contain_exactly(active_token) }
end
end end
describe '#token' do describe '#token' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment