PageRenderTime 47ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/ee/spec/models/ee/personal_access_token_spec.rb

https://gitlab.com/realsatomic/gitlab
Ruby | 326 lines | 274 code | 51 blank | 1 comment | 0 complexity | fc6ca6d28e850331bba2d6d48c91ca06 MD5 | raw file
  1. # frozen_string_literal: true
  2. require 'spec_helper'
  3. RSpec.describe PersonalAccessToken do
  4. describe 'scopes' do
  5. let_it_be(:expired_token) { create(:personal_access_token, expires_at: 1.day.ago) }
  6. let_it_be(:valid_token) { create(:personal_access_token, expires_at: 1.day.from_now) }
  7. let_it_be(:long_expiry_token) { create(:personal_access_token, expires_at: '999999-12-31'.to_date) }
  8. let!(:pat) { create(:personal_access_token, expires_at: expiration_date) }
  9. describe 'with_expires_at_after' do
  10. subject { described_class.with_expires_at_after(2.days.from_now) }
  11. let(:expiration_date) { 3.days.from_now }
  12. it 'includes the tokens with higher than the lifetime expires_at value' do
  13. expect(subject).to contain_exactly(pat, long_expiry_token)
  14. end
  15. it "doesn't contain expired tokens" do
  16. expect(subject).not_to include(expired_token)
  17. end
  18. it "doesn't contain tokens within the expiration time" do
  19. expect(subject).not_to include(valid_token)
  20. end
  21. end
  22. describe 'with_no_expires_at' do
  23. subject { described_class.with_expires_at_after(2.days.from_now) }
  24. let(:expiration_date) { nil }
  25. it 'includes the tokens with nil expires_at' do
  26. expect(described_class.with_no_expires_at).to contain_exactly(pat)
  27. end
  28. it "doesn't contain expired tokens" do
  29. expect(subject).not_to include(expired_token)
  30. end
  31. it "doesn't contain tokens within the expiration time" do
  32. expect(subject).not_to include(valid_token)
  33. end
  34. end
  35. describe 'expires_in' do
  36. subject { described_class.expires_in(1.day.from_now) }
  37. let(:expiration_date) { nil }
  38. it 'only includes one token' do
  39. expect(subject).to contain_exactly(valid_token)
  40. end
  41. end
  42. end
  43. describe 'validations' do
  44. let(:user) { build(:user) }
  45. let(:personal_access_token) { build(:personal_access_token, user: user) }
  46. it 'allows to define expires_at' do
  47. personal_access_token.expires_at = 1.day.from_now
  48. expect(personal_access_token).to be_valid
  49. end
  50. it "allows to don't define expires_at" do
  51. personal_access_token.expires_at = nil
  52. expect(personal_access_token).to be_valid
  53. end
  54. context 'with expiration policy' do
  55. let(:instance_level_pat_expiration_policy) { 30 }
  56. let(:instance_level_max_expiration_date) { instance_level_pat_expiration_policy.days.from_now }
  57. before do
  58. stub_ee_application_setting(max_personal_access_token_lifetime: instance_level_pat_expiration_policy)
  59. end
  60. shared_examples_for 'PAT expiry rules are not enforced' do
  61. it 'allows expiry to be after the max_personal_access_token_lifetime' do
  62. personal_access_token.expires_at = max_expiration_date + 1.day
  63. expect(personal_access_token).to be_valid
  64. end
  65. it 'can be blank' do
  66. personal_access_token.expires_at = nil
  67. expect(personal_access_token).to be_valid
  68. end
  69. end
  70. shared_examples_for 'PAT expiry rules are enforced' do
  71. it 'requires to be less or equal than the max_personal_access_token_lifetime' do
  72. personal_access_token.expires_at = max_expiration_date + 1.day
  73. expect(personal_access_token).not_to be_valid
  74. expect(personal_access_token.errors[:expires_at].first).to eq('is invalid')
  75. end
  76. it "can't be blank" do
  77. personal_access_token.expires_at = nil
  78. expect(personal_access_token).not_to be_valid
  79. expect(personal_access_token.errors[:expires_at].first).to eq("can't be blank")
  80. end
  81. end
  82. context 'when the feature is licensed' do
  83. before do
  84. stub_licensed_features(personal_access_token_expiration_policy: true)
  85. end
  86. context 'when the user does not belong to a managed group' do
  87. it_behaves_like 'PAT expiry rules are enforced' do
  88. let(:max_expiration_date) { instance_level_max_expiration_date }
  89. end
  90. end
  91. context 'when the user belongs to a managed group' do
  92. let(:group_level_pat_expiration_policy) { nil }
  93. let(:group) do
  94. build(:group_with_managed_accounts, max_personal_access_token_lifetime: group_level_pat_expiration_policy)
  95. end
  96. let(:user) { build(:user, managing_group: group) }
  97. context 'when the group has enforced a PAT expiry rule' do
  98. let(:group_level_pat_expiration_policy) { 20 }
  99. let(:group_level_max_expiration_date) { group_level_pat_expiration_policy.days.from_now }
  100. it_behaves_like 'PAT expiry rules are enforced' do
  101. let(:max_expiration_date) { group_level_max_expiration_date }
  102. end
  103. end
  104. context 'when the group has not enforced a PAT expiry setting' do
  105. context 'when the instance has enforced a PAT expiry setting' do
  106. it_behaves_like 'PAT expiry rules are enforced' do
  107. let(:max_expiration_date) { instance_level_max_expiration_date }
  108. end
  109. end
  110. context 'when the instance does not enforce a PAT expiry setting' do
  111. before do
  112. stub_ee_application_setting(max_personal_access_token_lifetime: nil)
  113. end
  114. it_behaves_like 'PAT expiry rules are not enforced' do
  115. let(:max_expiration_date) { instance_level_max_expiration_date }
  116. end
  117. end
  118. end
  119. end
  120. end
  121. context 'when the feature is not available' do
  122. before do
  123. stub_licensed_features(personal_access_token_expiration_policy: false)
  124. end
  125. it_behaves_like 'PAT expiry rules are not enforced' do
  126. let(:max_expiration_date) { instance_level_max_expiration_date }
  127. end
  128. end
  129. end
  130. end
  131. describe '.pluck_names' do
  132. it 'returns the names of the tokens' do
  133. pat1 = create(:personal_access_token)
  134. pat2 = create(:personal_access_token)
  135. expect(described_class.pluck_names).to contain_exactly(pat1.name, pat2.name)
  136. end
  137. end
  138. describe '.with_invalid_expires_at' do
  139. subject { described_class.with_invalid_expires_at(2.days.from_now) }
  140. it 'includes the tokens with invalid expires_at' do
  141. pat_with_no_expires_at = create(:personal_access_token, expires_at: nil)
  142. pat_with_longer_expires_at = create(:personal_access_token, expires_at: 3.days.from_now)
  143. expect(subject).to contain_exactly(pat_with_no_expires_at, pat_with_longer_expires_at)
  144. end
  145. it "doesn't include valid tokens" do
  146. valid_token = create(:personal_access_token, expires_at: 1.day.from_now)
  147. expect(subject).not_to include(valid_token)
  148. end
  149. it "doesn't include revoked tokens" do
  150. revoked_token = create(:personal_access_token, revoked: true)
  151. expect(subject).not_to include(revoked_token)
  152. end
  153. it "doesn't include expired tokens" do
  154. expired_token = create(:personal_access_token, expires_at: 1.day.ago)
  155. expect(subject).not_to include(expired_token)
  156. end
  157. end
  158. shared_examples 'enforcement of personal access token expiry' do
  159. using RSpec::Parameterized::TableSyntax
  160. where(:licensed, :application_setting, :result) do
  161. true | true | true
  162. true | false | false
  163. false | true | true
  164. false | false | true
  165. end
  166. with_them do
  167. before do
  168. stub_licensed_features(enforce_personal_access_token_expiration: licensed)
  169. stub_application_setting(enforce_pat_expiration: application_setting)
  170. end
  171. it { expect(subject).to be result }
  172. end
  173. end
  174. describe '.expiration_enforced??' do
  175. subject { described_class.expiration_enforced? }
  176. it_behaves_like 'enforcement of personal access token expiry'
  177. end
  178. describe '#expired?' do
  179. let_it_be(:expired_token) { create(:personal_access_token, expires_at: 1.week.ago) }
  180. subject { expired_token.expired? }
  181. it_behaves_like 'enforcement of personal access token expiry'
  182. end
  183. describe '#expired_but_not_enforced?' do
  184. using RSpec::Parameterized::TableSyntax
  185. subject { expired_token.expired_but_not_enforced? }
  186. where(:enforced?, :expires_at, :result) do
  187. true | 1.week.ago | false
  188. true | Time.current | false
  189. true | 1.week.from_now | false
  190. false | 1.week.ago | true
  191. false | Time.current | true
  192. false | 1.week.from_now | false
  193. end
  194. with_them do
  195. let_it_be(:expired_token) { build(:personal_access_token) }
  196. before do
  197. allow(described_class).to receive(:expiration_enforced?).and_return(enforced?)
  198. expired_token.expires_at = expires_at
  199. end
  200. it { expect(subject).to be result }
  201. end
  202. end
  203. describe '.enforce_pat_expiration_feature_available?' do
  204. using RSpec::Parameterized::TableSyntax
  205. subject { described_class.enforce_pat_expiration_feature_available? }
  206. where(:licensed, :result) do
  207. true | true
  208. false | false
  209. end
  210. with_them do
  211. before do
  212. stub_licensed_features(enforce_personal_access_token_expiration: licensed)
  213. end
  214. it { expect(subject).to be result }
  215. end
  216. end
  217. shared_context 'write to cache' do
  218. let_it_be(:pat) { create(:personal_access_token) }
  219. let_it_be(:cache_keys) { %w(token_expired_rotation token_expiring_rotation) }
  220. before do
  221. cache_keys.each do |key|
  222. Rails.cache.write(['users', pat.user.id, key], double)
  223. end
  224. end
  225. end
  226. describe '#revoke', :use_clean_rails_memory_store_caching do
  227. include_context 'write to cache'
  228. it 'clears cache on revoke access' do
  229. pat.revoke!
  230. cache_keys.each do |key|
  231. expect(Rails.cache.read(['users', pat.user.id, key])).to be_nil
  232. end
  233. end
  234. end
  235. describe 'after create callback', :use_clean_rails_memory_store_caching do
  236. include_context 'write to cache'
  237. it 'clears cache for the user' do
  238. create(:personal_access_token, user_id: pat.user_id)
  239. cache_keys.each do |key|
  240. expect(Rails.cache.read(['users', pat.user.id, key])).to be_nil
  241. end
  242. end
  243. end
  244. end