From d39fe0c66bbcf33288990863528e4c62bac81ed0 Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Wed, 4 Sep 2024 20:32:09 +0100 Subject: [PATCH] Fix SCC activations check when no product info is available When instance verification reaches SCC activations check without any product information available, the validation agreement is that all the activations must be active This Fixes bsc#1230157 --- .../v3/systems/activations_controller_spec.rb | 65 ++++++++++++++++++- engines/scc_proxy/lib/scc_proxy/engine.rb | 7 ++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/engines/registry/spec/requests/api/connect/v3/systems/activations_controller_spec.rb b/engines/registry/spec/requests/api/connect/v3/systems/activations_controller_spec.rb index a16896fbb..dd2cfcb73 100644 --- a/engines/registry/spec/requests/api/connect/v3/systems/activations_controller_spec.rb +++ b/engines/registry/spec/requests/api/connect/v3/systems/activations_controller_spec.rb @@ -3,7 +3,7 @@ include_context 'version header', 3 describe '#activations' do - let(:system) { FactoryBot.create(:system, :with_activated_product) } + let(:system) { FactoryBot.create(:system, :payg, :with_activated_product) } let(:headers) { auth_header.merge(version_header) } context 'without valid repository cache' do @@ -57,5 +57,68 @@ expect(data[0]['service']['url']).to match(%r{^plugin:/susecloud}) end end + + context 'system is hybrid' do + let(:system) { FactoryBot.create(:system, :hybrid, :with_activated_product) } + let(:plugin_double) { instance_double('InstanceVerification::Providers::Example') } + let(:cache_name) { "repo/cache/127.0.0.1-#{system.login}-#{system.products.first.id}" } + let(:scc_systems_activations_url) { 'https://scc.suse.com/connect/systems/activations' } + let(:body_active) do + { + id: 1, + regcode: '631dc51f', + name: 'Subscription 1', + type: 'FULL', + status: 'ACTIVE', + starts_at: 'null', + expires_at: '2014-03-14T13:10:21.164Z', + system_limit: 6, + systems_count: 1, + service: { + product: { + id: system.activations.first.product.id + } + } + } + end + + before do + allow(InstanceVerification::Providers::Example).to receive(:new).and_return(plugin_double) + + allow(plugin_double).to( + receive(:instance_valid?).and_return(true) + ) + allow(File).to receive(:join).and_call_original + allow(InstanceVerification).to receive(:update_cache) + allow(ZypperAuth).to receive(:verify_instance).and_call_original + stub_request(:get, scc_systems_activations_url).to_return(status: 200, body: [body_active].to_json, headers: {}) + headers['X-Instance-Data'] = 'IMDS' + end + + context 'no registry' do + it 'refreshes registry cache key only' do + FileUtils.mkdir_p('repo/cache') + expect(InstanceVerification).to receive(:update_cache).with('127.0.0.1', system.login, system.activations.first.product.id) + get '/connect/systems/activations', headers: headers + FileUtils.rm_rf('repo/cache') + data = JSON.parse(response.body) + expect(SccProxy).not_to receive(:product_path_access) + expect(data[0]['service']['url']).to match(%r{^plugin:/susecloud}) + end + end + + context 'registry' do + it 'refreshes registry cache key only' do + FileUtils.mkdir_p('repo/cache') + FileUtils.touch(cache_name) + expect(InstanceVerification).to receive(:update_cache).with('127.0.0.1', system.login, nil, registry: true) + get '/connect/systems/activations', headers: headers + FileUtils.rm_rf('repo/cache') + data = JSON.parse(response.body) + expect(SccProxy).not_to receive(:product_path_access) + expect(data[0]['service']['url']).to match(%r{^plugin:/susecloud}) + end + end + end end end diff --git a/engines/scc_proxy/lib/scc_proxy/engine.rb b/engines/scc_proxy/lib/scc_proxy/engine.rb index 378b87a99..d79e9479c 100644 --- a/engines/scc_proxy/lib/scc_proxy/engine.rb +++ b/engines/scc_proxy/lib/scc_proxy/engine.rb @@ -218,11 +218,17 @@ def product_class_access(scc_systems_activations, product) end end + # rubocop:disable Metrics/PerceivedComplexity def activations_fail_state(scc_systems_activations, headers, product = nil) return SccProxy.product_class_access(scc_systems_activations, product) unless product.nil? active_products_ids = scc_systems_activations.map { |act| act['service']['product']['id'] if act['status'].casecmp('active').zero? }.flatten x_original_uri = headers.fetch('X-Original-URI', '') + # if there is no product info to compare the activations with + # probably means the query is to refresh credentials + # in any case, verification is true if ALL activations are ACTIVE + return { is_active: (scc_systems_activations.length == active_products_ids.length) } if x_original_uri.empty? + if SccProxy.product_path_access(x_original_uri, active_products_ids) { is_active: true } else @@ -247,6 +253,7 @@ def activations_fail_state(scc_systems_activations, headers, product = nil) end end end + # rubocop:enable Metrics/PerceivedComplexity def scc_check_subscription_expiration(headers, login, system_token, logger, mode, product = nil) # rubocop:disable Metrics/ParameterLists response = SccProxy.get_scc_activations(headers, system_token, mode)