From 30b2bd973025a727e66de5f3aeb61caac7de9c0b Mon Sep 17 00:00:00 2001 From: Thomas Schmidt Date: Tue, 12 Mar 2024 17:26:24 +0100 Subject: [PATCH 01/39] skip tests that don't work with sqlite --- spec/lib/rmt/cli/smt_importer_spec.rb | 2 +- spec/lib/rmt/lockfile_spec.rb | 2 +- spec/lib/rmt/scc_spec.rb | 2 +- spec/models/repository_spec.rb | 6 +++--- spec/rails_helper.rb | 6 ++++++ spec/services/repository_service_spec.rb | 2 +- 6 files changed, 13 insertions(+), 7 deletions(-) diff --git a/spec/lib/rmt/cli/smt_importer_spec.rb b/spec/lib/rmt/cli/smt_importer_spec.rb index d77404a52..17063bbc0 100644 --- a/spec/lib/rmt/cli/smt_importer_spec.rb +++ b/spec/lib/rmt/cli/smt_importer_spec.rb @@ -1,7 +1,7 @@ require 'rails_helper' require 'rmt/cli/smt_importer' -describe RMT::CLI::SMTImporter do +describe RMT::CLI::SMTImporter, :skip_sqlite do let(:data_dir) { File.join(Dir.pwd, 'spec/fixtures/files/csv') } let(:no_systems) { false } let(:importer) { described_class.new(data_dir, no_systems) } diff --git a/spec/lib/rmt/lockfile_spec.rb b/spec/lib/rmt/lockfile_spec.rb index d1b86f968..c06644bc3 100644 --- a/spec/lib/rmt/lockfile_spec.rb +++ b/spec/lib/rmt/lockfile_spec.rb @@ -3,7 +3,7 @@ RSpec.describe RMT::Lockfile do let(:lock_name) { nil } - describe '#lock' do + describe '#lock', :skip_sqlite do subject(:lock) { described_class.lock(lock_name) { nil } } context 'with an unnamed lock' do diff --git a/spec/lib/rmt/scc_spec.rb b/spec/lib/rmt/scc_spec.rb index a4732b0cd..94b2a739d 100644 --- a/spec/lib/rmt/scc_spec.rb +++ b/spec/lib/rmt/scc_spec.rb @@ -238,7 +238,7 @@ described_class.new.sync end - it 'removes existing predecessor associations' do + it 'removes existing predecessor associations', :skip_sqlite do expect { ProductPredecessorAssociation.find(existing_association.id) }.to raise_error(ActiveRecord::RecordNotFound) end end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 3c958ac15..3c49cd6fa 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -146,7 +146,7 @@ expect(friendly_id).to eq('my-repo-100000') end - it 'appends with unicode within the chain' do + it 'appends with unicode within the chain', :skip_sqlite do create(:repository, friendly_id: 'my-repo') create(:repository, friendly_id: 'my-repö-1') expect(friendly_id).to eq('my-repo-2') @@ -165,13 +165,13 @@ expect(friendly_id).to eq('dümmy-repö') end - it 'appends with unicode within the chain' do + it 'appends with unicode within the chain', :skip_sqlite do create(:repository, friendly_id: 'dummy-repo') create(:repository, friendly_id: 'dümmy-repö-1') expect(friendly_id).to eq('dümmy-repö-2') end - it 'correctly appends' do + it 'correctly appends', :skip_sqlite do create(:repository, friendly_id: 'dummy-repo') create(:repository, friendly_id: 'dummy-repo-1') expect(friendly_id).to eq('dümmy-repö-2') diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 5d71fea9f..f5b47b1e6 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -58,6 +58,12 @@ config.filter_rails_from_backtrace! # arbitrary gems may also be filtered via: # config.filter_gems_from_backtrace("gem name") + + # Skipping some tests when running with (experimental) sqlite backend. + # Some tests / code parts are using specific mysql behavior + if ActiveRecord::Base.connection.adapter_name == 'SQLite' + config.filter_run_excluding :skip_sqlite => true + end end Shoulda::Matchers.configure do |config| diff --git a/spec/services/repository_service_spec.rb b/spec/services/repository_service_spec.rb index 1387ea3b0..0035395b5 100644 --- a/spec/services/repository_service_spec.rb +++ b/spec/services/repository_service_spec.rb @@ -88,7 +88,7 @@ it('is not custom') { expect(repository.custom?).to eq(true) } - context 'already existing repositories with changing URL' do + context 'already existing repositories with changing URL', :skip_sqlite do subject(:repository) do service.create_repository!(product, url, attributes, custom: custom).reload url = 'https://foo.bar.com/bar/foo' From d380414ae3bd537c464ed06ffaaf5fd439bd4f1a Mon Sep 17 00:00:00 2001 From: Thomas Schmidt Date: Tue, 12 Mar 2024 17:28:16 +0100 Subject: [PATCH 02/39] add step to ci to run tests with sqlite --- .github/workflows/lint-unit.yml | 5 +++++ spec/rails_helper.rb | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/lint-unit.yml b/.github/workflows/lint-unit.yml index 9ac44b6eb..66bf3f77c 100644 --- a/.github/workflows/lint-unit.yml +++ b/.github/workflows/lint-unit.yml @@ -83,6 +83,11 @@ jobs: run: | bundle exec rspec --format documentation + - name: Run core tests with sqlite + run: | + sed -i 's/adapter: mysql2/adapter: sqlite3/' config/rmt.yml + bundle exec rspec --format documentation + - name: Run PubCloud engines tests run: | bundle exec rake test:engines diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index f5b47b1e6..9c8bffe57 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -62,7 +62,7 @@ # Skipping some tests when running with (experimental) sqlite backend. # Some tests / code parts are using specific mysql behavior if ActiveRecord::Base.connection.adapter_name == 'SQLite' - config.filter_run_excluding :skip_sqlite => true + config.filter_run_excluding skip_sqlite: true end end From 59e62dff406f89d9a9dc170a973b4f4c9fe253b4 Mon Sep 17 00:00:00 2001 From: Natnael Getahun Date: Wed, 30 Oct 2024 10:03:04 +0100 Subject: [PATCH 03/39] Prepare rmt 2.20 release --- package/obs/rmt-server.changes | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/package/obs/rmt-server.changes b/package/obs/rmt-server.changes index febce557b..836bf566d 100644 --- a/package/obs/rmt-server.changes +++ b/package/obs/rmt-server.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Wed Oct 30 09:01:32 UTC 2024 - Natnael Getahun + +- Version 2.20 (unreleased) + * RMT packaging: make sync/mirror timer changes survive upgrade + ------------------------------------------------------------------- Wed Aug 21 15:28:43 UTC 2024 - Jesús Bermúdez Velázquez From 8d99b17075e8545dd44428b811edc03d7c65fe91 Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Thu, 7 Nov 2024 18:01:51 +0000 Subject: [PATCH 04/39] Add request to billing check The verification code will check the headers of @request object in order to access the content of SUMA headers to grant access Currently @request is nil coming from this code flow This add the request to the call --- .../instance_verification/billing_check_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/instance_verification/app/controllers/instance_verification/billing_check_controller.rb b/engines/instance_verification/app/controllers/instance_verification/billing_check_controller.rb index 9d00eee26..0217e54d7 100644 --- a/engines/instance_verification/app/controllers/instance_verification/billing_check_controller.rb +++ b/engines/instance_verification/app/controllers/instance_verification/billing_check_controller.rb @@ -5,7 +5,7 @@ def check # belongs to a PAYG or BYOS instance verification_provider = InstanceVerification.provider.new( logger, - nil, + request, nil, params[:metadata] ) From e4d40a6d643ece35c69cf0d3a0c4191c5ade875e Mon Sep 17 00:00:00 2001 From: Natnael Getahun Date: Mon, 11 Nov 2024 11:24:49 +0100 Subject: [PATCH 05/39] Update RandomizedDelaySec in systemd timers --- package/files/systemd/rmt-server-mirror.timer | 2 +- package/files/systemd/rmt-server-sync.timer | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package/files/systemd/rmt-server-mirror.timer b/package/files/systemd/rmt-server-mirror.timer index 33e37ea93..fb5bef680 100644 --- a/package/files/systemd/rmt-server-mirror.timer +++ b/package/files/systemd/rmt-server-mirror.timer @@ -3,7 +3,7 @@ Description=RMT Mirror timer [Timer] OnCalendar=*-*-* 02:00:00 -RandomizedDelaySec=9h +RandomizedDelaySec=15m Unit=rmt-server-mirror.service [Install] diff --git a/package/files/systemd/rmt-server-sync.timer b/package/files/systemd/rmt-server-sync.timer index 7a34b7545..7b393aebe 100644 --- a/package/files/systemd/rmt-server-sync.timer +++ b/package/files/systemd/rmt-server-sync.timer @@ -3,7 +3,7 @@ Description=RMT Sync timer [Timer] OnCalendar=*-*-* 01:00:00 -RandomizedDelaySec=9h +RandomizedDelaySec=15m Unit=rmt-server-sync.service [Install] From 1f685eb6e42783af5335567e68b3b1554eb16597 Mon Sep 17 00:00:00 2001 From: Natnael Getahun Date: Tue, 12 Nov 2024 10:30:50 +0100 Subject: [PATCH 06/39] Revert "Update RandomizedDelaySec in systemd timers" This reverts commit e4d40a6d643ece35c69cf0d3a0c4191c5ade875e. --- package/files/systemd/rmt-server-mirror.timer | 2 +- package/files/systemd/rmt-server-sync.timer | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package/files/systemd/rmt-server-mirror.timer b/package/files/systemd/rmt-server-mirror.timer index fb5bef680..33e37ea93 100644 --- a/package/files/systemd/rmt-server-mirror.timer +++ b/package/files/systemd/rmt-server-mirror.timer @@ -3,7 +3,7 @@ Description=RMT Mirror timer [Timer] OnCalendar=*-*-* 02:00:00 -RandomizedDelaySec=15m +RandomizedDelaySec=9h Unit=rmt-server-mirror.service [Install] diff --git a/package/files/systemd/rmt-server-sync.timer b/package/files/systemd/rmt-server-sync.timer index 7b393aebe..7a34b7545 100644 --- a/package/files/systemd/rmt-server-sync.timer +++ b/package/files/systemd/rmt-server-sync.timer @@ -3,7 +3,7 @@ Description=RMT Sync timer [Timer] OnCalendar=*-*-* 01:00:00 -RandomizedDelaySec=15m +RandomizedDelaySec=9h Unit=rmt-server-sync.service [Install] From 78646d29902cf67463075aa5acaf3e3f5f8385ef Mon Sep 17 00:00:00 2001 From: Natnael Getahun Date: Tue, 12 Nov 2024 10:35:01 +0100 Subject: [PATCH 07/39] Update RMT packaging --- package/obs/rmt-server.changes | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/package/obs/rmt-server.changes b/package/obs/rmt-server.changes index d1c4244f2..869af4633 100644 --- a/package/obs/rmt-server.changes +++ b/package/obs/rmt-server.changes @@ -2,8 +2,11 @@ Wed Oct 30 09:01:32 UTC 2024 - Natnael Getahun - Version 2.20 (unreleased) - * RMT packaging: make sync/mirror timer changes survive upgrade - + * RMT packaging: don't overwrite custom sync/mirror timer config on package update + * Extend column size for repository and file paths (bsc#1229152) + * rmt-server-pubcloud: + * Fix LTSS product verification (bsc#1230154) + * Fix activations check when no product info is available (bsc#1230157) ------------------------------------------------------------------- Wed Aug 21 15:28:43 UTC 2024 - Jesús Bermúdez Velázquez From f5679ae1430189000f7591e3aeaba63d1a6be1e6 Mon Sep 17 00:00:00 2001 From: Thomas Schmidt Date: Tue, 12 Nov 2024 17:03:42 +0100 Subject: [PATCH 08/39] Update rmt-server.changes --- package/obs/rmt-server.changes | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package/obs/rmt-server.changes b/package/obs/rmt-server.changes index 869af4633..ed80834ce 100644 --- a/package/obs/rmt-server.changes +++ b/package/obs/rmt-server.changes @@ -3,10 +3,12 @@ Wed Oct 30 09:01:32 UTC 2024 - Natnael Getahun - Version 2.20 (unreleased) * RMT packaging: don't overwrite custom sync/mirror timer config on package update - * Extend column size for repository and file paths (bsc#1229152) + * Extend column size for repository and file paths (bsc#1229152) + * Forward suseconnect client user-agents to SCC * rmt-server-pubcloud: * Fix LTSS product verification (bsc#1230154) * Fix activations check when no product info is available (bsc#1230157) + ------------------------------------------------------------------- Wed Aug 21 15:28:43 UTC 2024 - Jesús Bermúdez Velázquez From 4064c1e8e8a6efed18e862913534cab81783d98b Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Fri, 8 Nov 2024 15:30:41 +0000 Subject: [PATCH 09/39] Check for SLE Micro and SUMa headers to grant access SUMA 5.0 is based on SLE Micro, to access older SUMA versions we are using new headers present in the request to grant access to SUMA 4.X repositories --- .../authentication_controller.rb | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/engines/strict_authentication/app/controllers/strict_authentication/authentication_controller.rb b/engines/strict_authentication/app/controllers/strict_authentication/authentication_controller.rb index 311c38fc0..ec671999b 100644 --- a/engines/strict_authentication/app/controllers/strict_authentication/authentication_controller.rb +++ b/engines/strict_authentication/app/controllers/strict_authentication/authentication_controller.rb @@ -7,27 +7,28 @@ class AuthenticationController < ::ApplicationController # This is the endpoint for nginx subrequest auth check def check request_uri = request.headers['X-Original-URI'] - auth_result = path_allowed?(request.headers['X-Original-URI']) + auth_result = path_allowed?(request.headers) logger.info "Authentication subrequest for #{request_uri} -- #{auth_result ? 'allowed' : 'denied'}" head auth_result ? :ok : :forbidden end protected - def path_allowed?(path) + def path_allowed?(headers) + path = headers['X-Original-URI'] return false if path.blank? + return true if path =~ %r{/product\.license/} path = '/' + path.gsub(/^#{RMT::DEFAULT_MIRROR_URL_PREFIX}/, '') - # Allow access to SLES 12 and 12-SP1 repos for systems migrating from SLES 11 has_sles11 = @system.products.where(identifier: 'SUSE_SLES').first return true if (has_sles11 && (path =~ %r{/12/} || path =~ %r{/12-SP1/})) - all_allowed_paths.find { |allowed_path| path =~ /^#{Regexp.escape(allowed_path)}/ } + all_allowed_paths(headers).find { |allowed_path| path =~ /^#{Regexp.escape(allowed_path)}/ } end - def all_allowed_paths + def all_allowed_paths(headers) # return all versions of the same product and arch # (that the system has available with that subscription) # in order to validate access not only for current product but others @@ -39,7 +40,14 @@ def all_allowed_paths # for the SUMa PAYG offers, RMT access verification code allows access # to the SUMa Client Tools channels and SUMa Proxy channels # when product is SUMA_Server and PAYG or SUMA_Server and used as SCC proxy - manager_prod = @system.products.any? { |p| p.identifier.downcase.include?('manager-server') } + manager_prod = @system.products.any? do |p| + manager = p.identifier.downcase.include?('manager-server') + # SUMA 5.0 must have access to SUMA 4.3, 4.2 and so on + micro = p.identifier.downcase.include?('sle-micro') + instance_id_header = headers.fetch('X-Instance-Identifier', '').casecmp('suse-manager-server').zero? + instance_version_header = headers.fetch('X-Instance-Version', '') == '5.0' + manager || (micro && instance_id_header && instance_version_header) + end if manager_prod # add all SUMA products paths From 74ddfb87b167005a2d7c18ba21923aa28e16a72e Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Thu, 14 Nov 2024 10:24:44 +0000 Subject: [PATCH 10/39] Allow SLE Micro system to access free SLES repositories A SLE Micro system must have access to all free SLES repositories This Fixes bsc#1230419 --- .../connect/v3/systems/products_controller.rb | 8 ++++- .../authentication_controller.rb | 14 ++++++++ .../authentication_controller_spec.rb | 32 ++++++++++++++++++- spec/factories/products.rb | 16 ++++++++++ spec/factories/systems.rb | 11 +++++++ .../v3/systems/products_controller_spec.rb | 27 ++++++++++++++++ 6 files changed, 106 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/connect/v3/systems/products_controller.rb b/app/controllers/api/connect/v3/systems/products_controller.rb index 2545a9e92..62f5d9508 100644 --- a/app/controllers/api/connect/v3/systems/products_controller.rb +++ b/app/controllers/api/connect/v3/systems/products_controller.rb @@ -12,7 +12,13 @@ def activate end def show - if @system.products.include? @product + if @product.identifier.casecmp('sles').zero? + # if system has SLE Micro + # it should access to SLES products + sle_micro = @system.products.any? { |p| p.identifier.downcase.include?('sle-micro') } + sle_micro_same_arch = @system.products.pluck(:arch).include?(@product.arch) if sle_micro + end + if @system.products.include?(@product) || sle_micro_same_arch respond_with( @product, serializer: ::V3::ProductSerializer, diff --git a/engines/strict_authentication/app/controllers/strict_authentication/authentication_controller.rb b/engines/strict_authentication/app/controllers/strict_authentication/authentication_controller.rb index 311c38fc0..66351a2f5 100644 --- a/engines/strict_authentication/app/controllers/strict_authentication/authentication_controller.rb +++ b/engines/strict_authentication/app/controllers/strict_authentication/authentication_controller.rb @@ -36,6 +36,20 @@ def all_allowed_paths # to them or verify paths all_product_versions = @system.products.map { |p| Product.where(identifier: p.identifier, arch: p.arch) }.flatten allowed_paths = all_product_versions.map { |prod| prod.repositories.pluck(:local_path) }.flatten + # Allow SLE Micro to access all free SLES repositories + sle_micro = @system.products.any? { |p| p.identifier.downcase.include?('sle-micro') } + if sle_micro + system_products_archs = @system.products.pluck(:arch) + product_free_sles_modules_only = Product.where( + "(lower(identifier) like 'sle-module%' or lower(identifier) like 'packagehub') + and lower(identifier) not like '%sap%' + and arch = '#{system_products_archs.first}' + and free = 1" + ) + end + same_arch = product_free_sles_modules_only.any? { |p| system_products_archs.include?(p.arch) } if product_free_sles_modules_only.present? + allowed_paths += product_free_sles_modules_only.map { |prod| prod.repositories.pluck(:local_path) }.flatten if same_arch + # for the SUMa PAYG offers, RMT access verification code allows access # to the SUMa Client Tools channels and SUMa Proxy channels # when product is SUMA_Server and PAYG or SUMA_Server and used as SCC proxy diff --git a/engines/strict_authentication/spec/requests/strict_authentication/authentication_controller_spec.rb b/engines/strict_authentication/spec/requests/strict_authentication/authentication_controller_spec.rb index c921d3855..fcb5f4e03 100644 --- a/engines/strict_authentication/spec/requests/strict_authentication/authentication_controller_spec.rb +++ b/engines/strict_authentication/spec/requests/strict_authentication/authentication_controller_spec.rb @@ -5,7 +5,7 @@ module StrictAuthentication RSpec.describe AuthenticationController, type: :request do subject { response } - let(:system) { FactoryBot.create(:system, :with_activated_product) } + let(:system) { FactoryBot.create(:system, :with_activated_product_sle_micro) } describe '#check' do context 'without authentication' do @@ -39,6 +39,36 @@ module StrictAuthentication its(:code) { is_expected.to eq '403' } end + context 'when requesting a file in an activated SLES repo on a SLE Micro system' do + let(:free_product) do + prod = FactoryBot.create( + :product, :module, :with_mirrored_repositories + ) + prod.identifier = 'sle-module-foo' + prod.arch = system.products.first.arch + prod.save! + prod + end + let(:requested_uri) { '/repo' + free_product.repositories.first[:local_path] + '/repodata/repomd.xml' } + + its(:code) { is_expected.to eq '200' } + end + + context 'when requesting a file in an activated SLES SAP repo on a SLE Micro system' do + let(:free_product) do + prod = FactoryBot.create( + :product, :module, :with_mirrored_repositories + ) + prod.identifier = 'sle-module-foo-sap' + prod.arch = system.products.first.arch + prod.save! + prod + end + let(:requested_uri) { '/repo' + free_product.repositories.first[:local_path] + '/repodata/repomd.xml' } + + its(:code) { is_expected.to eq '403' } + end + context 'when requesting a file in an activated repo' do let(:requested_uri) { '/repo' + system.repositories.first[:local_path] + '/repodata/repomd.xml' } diff --git a/spec/factories/products.rb b/spec/factories/products.rb index 30532e1fc..0f8701fce 100644 --- a/spec/factories/products.rb +++ b/spec/factories/products.rb @@ -73,6 +73,22 @@ friendly_version { '15 SP3' } end + trait :product_sle_micro do + identifier { 'SLE-Micro' } + name { 'SUSE Linux Enterprise Server' } + description { 'SUSE Linux Enterprise offers a comprehensive suite of products...' } + shortname { 'SLES15-SP6' } + former_identifier { 'SUSE_SLES_MICRO' } + product_type { :base } + release_type { nil } + release_stage { 'released' } + version { '15.6' } + arch { 'x86_64' } + free { false } + cpe { 'cpe:/o:suse:sles_sap:15:sp6' } + friendly_version { '15 SP6' } + end + trait :extension do product_type { 'extension' } end diff --git a/spec/factories/systems.rb b/spec/factories/systems.rb index 8fb81aa38..ceab7d02e 100644 --- a/spec/factories/systems.rb +++ b/spec/factories/systems.rb @@ -57,6 +57,17 @@ end end + trait :with_activated_product_sle_micro do + transient do + product { create(:product, :product_sle_micro, :with_mirrored_repositories) } + subscription { nil } + end + + after :create do |system, evaluator| + create(:activation, system: system, service: evaluator.product.service, subscription: evaluator.subscription) + end + end + trait :with_system_information do system_information do { diff --git a/spec/requests/api/connect/v3/systems/products_controller_spec.rb b/spec/requests/api/connect/v3/systems/products_controller_spec.rb index 60c1bbb0d..457a77d65 100644 --- a/spec/requests/api/connect/v3/systems/products_controller_spec.rb +++ b/spec/requests/api/connect/v3/systems/products_controller_spec.rb @@ -246,6 +246,33 @@ end end + context 'when SLE Micro product is activated' do + let(:system) { FactoryBot.create(:system, :with_activated_product_sle_micro) } + let(:product) { FactoryBot.create(:product, :product_sles, :with_mirrored_repositories) } + let(:payload) do + { + identifier: product.identifier, + version: product.version, + arch: system.products.first.arch + } + end + let(:serialized_json) do + V3::ProductSerializer.new( + product, + base_url: URI::HTTP.build({ scheme: response.request.scheme, host: response.request.host }).to_s + ).to_json + end + + describe 'response' do + subject { response } + + before { get url, headers: headers, params: payload } + + its(:code) { is_expected.to eq('200') } + its(:body) { is_expected.to eq(serialized_json) } + end + end + context 'with eula_url' do subject { response } From f126c1e12ae1bdbff647973275a867c62fc6972e Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Thu, 21 Nov 2024 03:03:32 +0000 Subject: [PATCH 11/39] Azure basic images do not get access to LTSS --- .../providers/example.rb | 4 + .../v3/systems/products_controller_spec.rb | 4 +- engines/scc_proxy/lib/scc_proxy/engine.rb | 9 ++ .../v3/systems/products_controller_spec.rb | 117 +++++++++++++++++- spec/factories/products.rb | 17 +++ spec/factories/systems.rb | 13 ++ 6 files changed, 160 insertions(+), 4 deletions(-) diff --git a/engines/instance_verification/lib/instance_verification/providers/example.rb b/engines/instance_verification/lib/instance_verification/providers/example.rb index b773d7855..1d49f92d9 100644 --- a/engines/instance_verification/lib/instance_verification/providers/example.rb +++ b/engines/instance_verification/lib/instance_verification/providers/example.rb @@ -49,4 +49,8 @@ def payg_billing_code?(iid, identifier) return true if (identifier.casecmp('sles').zero? && instance_billing_info[:billing_product] == SLES_PRODUCT_IDENTIFIER) return true if (identifier.casecmp('sles_sap').zero? && SLES4SAP_PRODUCT_IDENTIFIER.include?(instance_billing_info[:marketplace_code])) end + + def basic? + false + end end diff --git a/engines/instance_verification/spec/requests/api/connect/v3/systems/products_controller_spec.rb b/engines/instance_verification/spec/requests/api/connect/v3/systems/products_controller_spec.rb index 9ccbcb1c2..f3e2940c6 100644 --- a/engines/instance_verification/spec/requests/api/connect/v3/systems/products_controller_spec.rb +++ b/engines/instance_verification/spec/requests/api/connect/v3/systems/products_controller_spec.rb @@ -123,7 +123,7 @@ context 'when system has hw_info' do let(:instance_data) { 'dummy_instance_data' } - let(:system) { FactoryBot.create(:system, :payg, :with_system_information, instance_data: instance_data) } + let(:system) { FactoryBot.create(:system, :payg, :with_system_information_az, instance_data: instance_data) } let(:serialized_service_json) do V3::ServiceSerializer.new( product.service, @@ -188,7 +188,7 @@ let(:instance_data) { 'dummy_instance_data' } let(:system) do FactoryBot.create( - :system, :payg, :with_system_information, :with_activated_product, product: base_product, instance_data: instance_data + :system, :payg, :with_system_information_az, :with_activated_product, product: base_product, instance_data: instance_data ) end let(:serialized_service_json) do diff --git a/engines/scc_proxy/lib/scc_proxy/engine.rb b/engines/scc_proxy/lib/scc_proxy/engine.rb index e684dc910..d89967837 100644 --- a/engines/scc_proxy/lib/scc_proxy/engine.rb +++ b/engines/scc_proxy/lib/scc_proxy/engine.rb @@ -372,6 +372,15 @@ def has_no_regcode?(auth_header) protected def scc_activate_product + if (@system.system_information && + JSON.parse(@system.system_information)['cloud_provider'].casecmp('microsoft').zero? && + @product.product_class.downcase.include?('ltss') && + InstanceVerification.provider.new(logger, request, nil, @system.instance_data).basic? + ) + error = ActionController::TranslatedError.new(N_('Product not supported for this instance')) + error.status = :forbidden + raise error + end mode = find_mode unless mode.nil? # if system is byos or hybrid and there is a token diff --git a/engines/scc_proxy/spec/requests/api/connect/v3/systems/products_controller_spec.rb b/engines/scc_proxy/spec/requests/api/connect/v3/systems/products_controller_spec.rb index 0ff8417f3..6494c9bd7 100644 --- a/engines/scc_proxy/spec/requests/api/connect/v3/systems/products_controller_spec.rb +++ b/engines/scc_proxy/spec/requests/api/connect/v3/systems/products_controller_spec.rb @@ -349,12 +349,12 @@ context 'when system is connected to SCC' do let(:system_payg) do - FactoryBot.create(:system, :payg, :with_system_information, :with_activated_base_product, instance_data: instance_data, + FactoryBot.create(:system, :payg, :with_system_information_az, :with_activated_base_product, instance_data: instance_data, system_token: new_system_token) end let(:product) do FactoryBot.create( - :product, :product_sles, :extension, :with_mirrored_repositories, :with_mirrored_extensions, + :product, :product_sles_ltss, :extension, :with_mirrored_repositories, :with_mirrored_extensions, base_products: [system_payg.products.first] ) end @@ -415,7 +415,120 @@ allow(File).to receive(:directory?) allow(FileUtils).to receive(:mkdir_p) allow(FileUtils).to receive(:touch) + allow(InstanceVerification::Providers::Example).to receive(:new).and_return(plugin_double) + allow(plugin_double).to receive(:basic?).and_return(false) + allow(InstanceVerification).to receive(:write_cache_file).twice.with( + Rails.application.config.repo_cache_dir, "127.0.0.1-#{system_payg.login}-#{product.id}" + ) + allow(InstanceVerification).to receive(:write_cache_file).twice.with( + Rails.application.config.registry_cache_dir, "127.0.0.1-#{system_payg.login}" + ) + allow(plugin_double).to receive(:instance_valid?).and_return(true) + end + + context 'when LTSS not allowed' do + before do + allow(plugin_double).to receive(:basic?).and_return(true) + end + + it 'raises an error' do + stub_request(:post, scc_register_system_url) + .to_return(status: 403, body: { ok: 'OK' }.to_json, headers: {}) + + post url, params: payload, headers: headers + data = JSON.parse(response.body) + expect(data['error']).to include('Product not supported for this instance') + end + end + end + end + end + + context 'when system has hw_info' do + let(:instance_data) { '{"instanceId": "dummy_instance_data"}' } + let(:new_system_token) { 'BBBBBBBB-BBBB-4BBB-9BBB-BBBBBBBBBBBB' } + let(:serialized_service_json) do + V3::ServiceSerializer.new( + product.service, + base_url: URI::HTTP.build({ scheme: response.request.scheme, host: response.request.host }).to_s + ).to_json + end + + let(:serialized_service_sap_json) do + V3::ServiceSerializer.new( + product_sap.service, + base_url: URI::HTTP.build({ scheme: response.request.scheme, host: response.request.host }).to_s + ).to_json + end + + context 'when system is connected to SCC' do + let(:system_payg) do + FactoryBot.create(:system, :payg, :with_system_information_az, :with_activated_base_product, instance_data: instance_data, + system_token: new_system_token) + end + let(:product) do + FactoryBot.create( + :product, :product_sles_ltss, :extension, :with_mirrored_repositories, :with_mirrored_extensions, + base_products: [system_payg.products.first] + ) + end + let(:subscription_response) do + { + id: 4206714, + regcode: 'bar', + name: 'SUSE Employee subscription for SUSE Linux Enterprise Server for SAP Applications', + type: 'internal', + status: 'ACTIVE', + starts_at: '2019-03-20T09:48:52.658Z', + expires_at: '2024-03-20T09:48:52.658Z', + system_limit: '100', + systems_count: '156', + virtual_count: nil, + product_classes: [ + 'AiO', + '7261', + 'SLE-HAE-X86', + '7261-BETA', + 'SLE-HAE-X86-BETA', + 'AiO-BETA', + '7261-ALPHA', + 'SLE-HAE-X86-ALPHA', + 'AiO-ALPHA' + ], + product_ids: [ + 1959, + 1421 + ], + skus: [], + systems: [ + { + id: 3021957, + login: 'SCC_foo', + password: '5ee7273ac6ac4d7f', + last_seen_at: '2019-03-20T14:01:05.424Z' + } + ] + } + end + + before do + allow(plugin_double).to( + receive(:instance_valid?) + .and_raise(InstanceVerification::Exception, 'Custom plugin error') + ) + end + context 'with a valid registration code' do + before do + stub_request(:post, scc_activate_url) + .to_return( + status: 201, + body: { id: 'bar' }.to_json, + headers: {} + ) + allow(File).to receive(:directory?) + allow(FileUtils).to receive(:mkdir_p) + allow(FileUtils).to receive(:touch) allow(InstanceVerification).to receive(:write_cache_file).twice.with( Rails.application.config.repo_cache_dir, "127.0.0.1-#{system_payg.login}-#{product.id}" ) diff --git a/spec/factories/products.rb b/spec/factories/products.rb index 30532e1fc..e11965e7a 100644 --- a/spec/factories/products.rb +++ b/spec/factories/products.rb @@ -57,6 +57,23 @@ friendly_version { '15 SP3' } end + trait :product_sles_ltss do + identifier { 'SLES-LTSS' } + name { 'SUSE Linux Enterprise Server LTSS' } + description { 'SUSE Linux Enterprise offers a comprehensive suite of products...' } + shortname { 'SLES15-SP3-LTSS' } + former_identifier { 'SLES_LTSS' } + product_type { 'extension' } + product_class { 'LTSS' } + release_type { nil } + release_stage { 'released' } + version { '15.3' } + arch { 'x86_64' } + free { false } + cpe { 'cpe:/o:suse:sles:15:sp3' } + friendly_version { '15 SP3' } + end + trait :product_sles_sap do identifier { 'SLES_SAP' } name { 'SUSE Linux Enterprise Server' } diff --git a/spec/factories/systems.rb b/spec/factories/systems.rb index 8fb81aa38..2f3197f36 100644 --- a/spec/factories/systems.rb +++ b/spec/factories/systems.rb @@ -70,6 +70,19 @@ end end + trait :with_system_information_az do + system_information do + { + cpus: 2, + sockets: 1, + hypervisor: nil, + arch: 'x86_64', + uuid: SecureRandom.uuid, + cloud_provider: 'Microsoft' + }.to_json + end + end + trait :with_system_token do sequence(:system_token) { |n| "00000000-0000-4000-9000-#{n.to_s.rjust(12, '0')}" } end From 50d74dc426f4888c436727829d74e6731f6895bd Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Thu, 21 Nov 2024 03:10:57 +0000 Subject: [PATCH 12/39] Fix rubocop --- engines/scc_proxy/lib/scc_proxy/engine.rb | 2 ++ .../requests/api/connect/v3/systems/products_controller_spec.rb | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/engines/scc_proxy/lib/scc_proxy/engine.rb b/engines/scc_proxy/lib/scc_proxy/engine.rb index d89967837..8a744a036 100644 --- a/engines/scc_proxy/lib/scc_proxy/engine.rb +++ b/engines/scc_proxy/lib/scc_proxy/engine.rb @@ -307,6 +307,7 @@ def scc_upgrade(auth, product, system_login, mode, logger) end end + # rubocop:disable Metrics/ClassLength class Engine < ::Rails::Engine isolate_namespace SccProxy config.generators.api_only = true @@ -549,5 +550,6 @@ def get_system(systems) end end end + # rubocop:enable Metrics/ClassLength end # rubocop:enable Metrics/ModuleLength diff --git a/engines/scc_proxy/spec/requests/api/connect/v3/systems/products_controller_spec.rb b/engines/scc_proxy/spec/requests/api/connect/v3/systems/products_controller_spec.rb index 6494c9bd7..1e11f91e9 100644 --- a/engines/scc_proxy/spec/requests/api/connect/v3/systems/products_controller_spec.rb +++ b/engines/scc_proxy/spec/requests/api/connect/v3/systems/products_controller_spec.rb @@ -444,7 +444,7 @@ end end - context 'when system has hw_info' do + context 'when system has hw info' do let(:instance_data) { '{"instanceId": "dummy_instance_data"}' } let(:new_system_token) { 'BBBBBBBB-BBBB-4BBB-9BBB-BBBBBBBBBBBB' } let(:serialized_service_json) do From 91552ef18baafa52d82605482d18b169cf1b3a6e Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Thu, 21 Nov 2024 17:53:33 +0000 Subject: [PATCH 13/39] Allow extension no CSP specific Prepare the condition for any CSPs Rename method to be generic --- .../providers/example.rb | 6 +++-- .../v3/systems/products_controller_spec.rb | 25 ++++++++++++------- engines/scc_proxy/lib/scc_proxy/engine.rb | 7 ++---- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/engines/instance_verification/lib/instance_verification/providers/example.rb b/engines/instance_verification/lib/instance_verification/providers/example.rb index 1d49f92d9..46bca7fc0 100644 --- a/engines/instance_verification/lib/instance_verification/providers/example.rb +++ b/engines/instance_verification/lib/instance_verification/providers/example.rb @@ -50,7 +50,9 @@ def payg_billing_code?(iid, identifier) return true if (identifier.casecmp('sles_sap').zero? && SLES4SAP_PRODUCT_IDENTIFIER.include?(instance_billing_info[:marketplace_code])) end - def basic? - false + def allowed_extension? + # method to check if a product (extension) meet the criteria + # to be acivated on SCC or not, i.e. LTSS in Azure Basic VM + true end end diff --git a/engines/instance_verification/spec/requests/api/connect/v3/systems/products_controller_spec.rb b/engines/instance_verification/spec/requests/api/connect/v3/systems/products_controller_spec.rb index f3e2940c6..da9f6bc4a 100644 --- a/engines/instance_verification/spec/requests/api/connect/v3/systems/products_controller_spec.rb +++ b/engines/instance_verification/spec/requests/api/connect/v3/systems/products_controller_spec.rb @@ -38,7 +38,7 @@ it 'class instance verification provider' do expect(InstanceVerification::Providers::Example).to receive(:new) - .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, nil).and_call_original + .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, nil).and_call_original.at_least(:once) allow(File).to receive(:directory?) allow(Dir).to receive(:mkdir) allow(FileUtils).to receive(:touch) @@ -71,13 +71,17 @@ end context 'when verification provider returns false' do + # let(:plugin_double) { instance_double('InstanceVerification::Providers::Example') } + before do stub_request(:post, scc_activate_url) .to_return( status: 200, body: { error: 'Unexpected instance verification error has occurred' }.to_json, headers: {} - ) + ) + # allow(InstanceVerification::Providers::Example).to receive(:new).and_return(plugin_double) + # allow(plugin_double).to receive(:allowed_extension?).and_return(true) post url, params: payload, headers: headers end @@ -113,7 +117,7 @@ it 'class instance verification provider' do expect(InstanceVerification::Providers::Example).to receive(:new) - .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, nil).and_call_original + .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, nil).and_call_original.at_least(:once) allow(File).to receive(:directory?) allow(Dir).to receive(:mkdir) allow(FileUtils).to receive(:touch) @@ -123,7 +127,7 @@ context 'when system has hw_info' do let(:instance_data) { 'dummy_instance_data' } - let(:system) { FactoryBot.create(:system, :payg, :with_system_information_az, instance_data: instance_data) } + let(:system) { FactoryBot.create(:system, :payg, :with_system_information, instance_data: instance_data) } let(:serialized_service_json) do V3::ServiceSerializer.new( product.service, @@ -188,7 +192,7 @@ let(:instance_data) { 'dummy_instance_data' } let(:system) do FactoryBot.create( - :system, :payg, :with_system_information_az, :with_activated_product, product: base_product, instance_data: instance_data + :system, :payg, :with_system_information, :with_activated_product, product: base_product, instance_data: instance_data ) end let(:serialized_service_json) do @@ -340,8 +344,9 @@ before do allow(InstanceVerification::Providers::Example).to receive(:new) - .with(nil, nil, nil, instance_data).and_return(plugin_double) + .and_return(plugin_double) allow(plugin_double).to receive(:parse_instance_data).and_return({ InstanceId: 'foo' }) + allow(plugin_double).to receive(:allowed_extension?).and_return(true) allow(InstanceVerification).to receive(:update_cache).with('127.0.0.1', system.login, product.id) FactoryBot.create(:subscription, product_classes: product_classes) @@ -380,8 +385,9 @@ before do allow(InstanceVerification::Providers::Example).to receive(:new) - .with(nil, nil, nil, instance_data).and_return(plugin_double) + .and_return(plugin_double) allow(plugin_double).to receive(:parse_instance_data).and_return({ InstanceId: 'foo' }) + allow(plugin_double).to receive(:allowed_extension?).and_return(true) allow(InstanceVerification).to receive(:update_cache).with('127.0.0.1', system.login, product.id) FactoryBot.create(:subscription, product_classes: product_classes) @@ -414,7 +420,7 @@ it 'class instance verification provider' do expect(InstanceVerification::Providers::Example).to receive(:new) - .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, nil).and_call_original + .and_call_original.at_least(:once) allow(File).to receive(:directory?) allow(Dir).to receive(:mkdir) allow(FileUtils).to receive(:touch) @@ -514,8 +520,9 @@ before do allow(InstanceVerification::Providers::Example).to receive(:new) - .with(nil, nil, nil, instance_data).and_return(plugin_double) + .and_return(plugin_double) allow(plugin_double).to receive(:parse_instance_data).and_return({ InstanceId: 'foo' }) + allow(plugin_double).to receive(:allowed_extension?).and_return(true) FactoryBot.create(:subscription, product_classes: product_classes) stub_request(:post, scc_activate_url) diff --git a/engines/scc_proxy/lib/scc_proxy/engine.rb b/engines/scc_proxy/lib/scc_proxy/engine.rb index 8a744a036..95be2a642 100644 --- a/engines/scc_proxy/lib/scc_proxy/engine.rb +++ b/engines/scc_proxy/lib/scc_proxy/engine.rb @@ -373,11 +373,8 @@ def has_no_regcode?(auth_header) protected def scc_activate_product - if (@system.system_information && - JSON.parse(@system.system_information)['cloud_provider'].casecmp('microsoft').zero? && - @product.product_class.downcase.include?('ltss') && - InstanceVerification.provider.new(logger, request, nil, @system.instance_data).basic? - ) + product_hash = @product.attributes.symbolize_keys.slice(:identifier, :version, :arch) + unless InstanceVerification.provider.new(logger, request, product_hash, @system.instance_data).allowed_extension? error = ActionController::TranslatedError.new(N_('Product not supported for this instance')) error.status = :forbidden raise error From f544bb04766999d1d7f7db8b28c5a3e7ab65fc35 Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Mon, 25 Nov 2024 10:04:00 +0000 Subject: [PATCH 14/39] Update tests --- .../connect/v3/systems/products_controller_spec.rb | 8 ++++---- spec/factories/systems.rb | 13 ------------- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/engines/scc_proxy/spec/requests/api/connect/v3/systems/products_controller_spec.rb b/engines/scc_proxy/spec/requests/api/connect/v3/systems/products_controller_spec.rb index 1e11f91e9..f023a15b9 100644 --- a/engines/scc_proxy/spec/requests/api/connect/v3/systems/products_controller_spec.rb +++ b/engines/scc_proxy/spec/requests/api/connect/v3/systems/products_controller_spec.rb @@ -349,7 +349,7 @@ context 'when system is connected to SCC' do let(:system_payg) do - FactoryBot.create(:system, :payg, :with_system_information_az, :with_activated_base_product, instance_data: instance_data, + FactoryBot.create(:system, :payg, :with_system_information, :with_activated_base_product, instance_data: instance_data, system_token: new_system_token) end let(:product) do @@ -416,7 +416,7 @@ allow(FileUtils).to receive(:mkdir_p) allow(FileUtils).to receive(:touch) allow(InstanceVerification::Providers::Example).to receive(:new).and_return(plugin_double) - allow(plugin_double).to receive(:basic?).and_return(false) + allow(plugin_double).to receive(:allowed_extension?).and_return(true) allow(InstanceVerification).to receive(:write_cache_file).twice.with( Rails.application.config.repo_cache_dir, "127.0.0.1-#{system_payg.login}-#{product.id}" ) @@ -428,7 +428,7 @@ context 'when LTSS not allowed' do before do - allow(plugin_double).to receive(:basic?).and_return(true) + allow(plugin_double).to receive(:allowed_extension?).and_return(false) end it 'raises an error' do @@ -463,7 +463,7 @@ context 'when system is connected to SCC' do let(:system_payg) do - FactoryBot.create(:system, :payg, :with_system_information_az, :with_activated_base_product, instance_data: instance_data, + FactoryBot.create(:system, :payg, :with_system_information, :with_activated_base_product, instance_data: instance_data, system_token: new_system_token) end let(:product) do diff --git a/spec/factories/systems.rb b/spec/factories/systems.rb index 2f3197f36..8fb81aa38 100644 --- a/spec/factories/systems.rb +++ b/spec/factories/systems.rb @@ -70,19 +70,6 @@ end end - trait :with_system_information_az do - system_information do - { - cpus: 2, - sockets: 1, - hypervisor: nil, - arch: 'x86_64', - uuid: SecureRandom.uuid, - cloud_provider: 'Microsoft' - }.to_json - end - end - trait :with_system_token do sequence(:system_token) { |n| "00000000-0000-4000-9000-#{n.to_s.rjust(12, '0')}" } end From f7c3ae5d01d1fd68d57fe479dbfe310d97018d0f Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Mon, 25 Nov 2024 11:26:36 +0000 Subject: [PATCH 15/39] Send the instance ID in the token for Azure When activating an extension, i.e. LTSS in Azure, the header must contain the the instance identifier This Fixes bsc#1233314 --- engines/scc_proxy/lib/scc_proxy/engine.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/engines/scc_proxy/lib/scc_proxy/engine.rb b/engines/scc_proxy/lib/scc_proxy/engine.rb index e684dc910..10eede7bf 100644 --- a/engines/scc_proxy/lib/scc_proxy/engine.rb +++ b/engines/scc_proxy/lib/scc_proxy/engine.rb @@ -68,9 +68,10 @@ def get_instance_id(params) nil, params['instance_data'] ) - instance_id_key = INSTANCE_ID_KEYS[params['hwinfo']['cloud_provider'].downcase.to_sym] - iid = verification_provider.parse_instance_data - iid[instance_id_key] + csp = params['hwinfo']['cloud_provider'].downcase + instance_id_key = INSTANCE_ID_KEYS[csp.to_sym] + instance_data = verification_provider.parse_instance_data + csp.casecmp('microsoft').zero? ? instance_data['attestedData'][instance_id_key] : instance_data[instance_id_key] end def prepare_scc_announce_request(uri_path, auth, params) From ddcb893660e08ae49a81d66edaa55659d18ddfea Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Mon, 25 Nov 2024 16:13:35 +0000 Subject: [PATCH 16/39] Add instance_identifier method In order to keep RMT implementation generic add a CSP specific method in the CSP instance verification class --- .../providers/example.rb | 8 ++++---- .../v3/systems/products_controller_spec.rb | 2 +- engines/scc_proxy/lib/scc_proxy/engine.rb | 20 ++++++------------- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/engines/instance_verification/lib/instance_verification/providers/example.rb b/engines/instance_verification/lib/instance_verification/providers/example.rb index b773d7855..780c57884 100644 --- a/engines/instance_verification/lib/instance_verification/providers/example.rb +++ b/engines/instance_verification/lib/instance_verification/providers/example.rb @@ -27,10 +27,6 @@ def validate_instance_data(_instance_data) end def parse_instance_data - if @instance_data.include? '' - return { 'instance_data' => 'parsed_instance_data' } - end - if @instance_data.include?('SUSE') if @instance_data.include?('SAP') return { 'billingProducts' => nil, 'marketplaceProductCodes' => ['6789_SUSE_SAP'] } @@ -49,4 +45,8 @@ def payg_billing_code?(iid, identifier) return true if (identifier.casecmp('sles').zero? && instance_billing_info[:billing_product] == SLES_PRODUCT_IDENTIFIER) return true if (identifier.casecmp('sles_sap').zero? && SLES4SAP_PRODUCT_IDENTIFIER.include?(instance_billing_info[:marketplace_code])) end + + def instance_identifier + 'foo' + end end diff --git a/engines/instance_verification/spec/requests/api/connect/v3/systems/products_controller_spec.rb b/engines/instance_verification/spec/requests/api/connect/v3/systems/products_controller_spec.rb index 9ccbcb1c2..40b079e2f 100644 --- a/engines/instance_verification/spec/requests/api/connect/v3/systems/products_controller_spec.rb +++ b/engines/instance_verification/spec/requests/api/connect/v3/systems/products_controller_spec.rb @@ -341,7 +341,7 @@ before do allow(InstanceVerification::Providers::Example).to receive(:new) .with(nil, nil, nil, instance_data).and_return(plugin_double) - allow(plugin_double).to receive(:parse_instance_data).and_return({ InstanceId: 'foo' }) + allow(plugin_double).to receive(:instance_identifier).and_return('foo') allow(InstanceVerification).to receive(:update_cache).with('127.0.0.1', system.login, product.id) FactoryBot.create(:subscription, product_classes: product_classes) diff --git a/engines/scc_proxy/lib/scc_proxy/engine.rb b/engines/scc_proxy/lib/scc_proxy/engine.rb index 10eede7bf..5da34dd14 100644 --- a/engines/scc_proxy/lib/scc_proxy/engine.rb +++ b/engines/scc_proxy/lib/scc_proxy/engine.rb @@ -43,7 +43,12 @@ class << self # rubocop:disable ThreadSafety/InstanceVariableInClassMethod def headers(auth, params) @instance_id = if params && params.class != String - get_instance_id(params) + InstanceVerification.provider.new( + nil, + nil, + nil, + params['instance_data'] + ).instance_identifier else # if it is not JSON, it is the system_token already # announce system has metadata @@ -61,19 +66,6 @@ def headers(auth, params) end # rubocop:enable ThreadSafety/InstanceVariableInClassMethod - def get_instance_id(params) - verification_provider = InstanceVerification.provider.new( - nil, - nil, - nil, - params['instance_data'] - ) - csp = params['hwinfo']['cloud_provider'].downcase - instance_id_key = INSTANCE_ID_KEYS[csp.to_sym] - instance_data = verification_provider.parse_instance_data - csp.casecmp('microsoft').zero? ? instance_data['attestedData'][instance_id_key] : instance_data[instance_id_key] - end - def prepare_scc_announce_request(uri_path, auth, params) scc_request = Net::HTTP::Post.new(uri_path, headers(auth, params)) From 40fb93f7803838d08a1b20614c71300d3eb4423b Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Mon, 25 Nov 2024 16:16:18 +0000 Subject: [PATCH 17/39] Remove variable as it will be CSP specific --- engines/scc_proxy/lib/scc_proxy/engine.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/engines/scc_proxy/lib/scc_proxy/engine.rb b/engines/scc_proxy/lib/scc_proxy/engine.rb index 5da34dd14..b6905d4a0 100644 --- a/engines/scc_proxy/lib/scc_proxy/engine.rb +++ b/engines/scc_proxy/lib/scc_proxy/engine.rb @@ -25,12 +25,6 @@ Net::HTTPRetriableError ].freeze -INSTANCE_ID_KEYS = { - amazon: 'instanceId', - google: 'instance_id', - microsoft: 'vmId' -}.freeze - # rubocop:disable Metrics/ModuleLength module SccProxy class << self From a778f30e302145ca2499cc2024a0c10c151db70f Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Tue, 26 Nov 2024 10:00:14 +0000 Subject: [PATCH 18/39] Fix CI test --- .../v3/systems/products_controller_spec.rb | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/engines/instance_verification/spec/requests/api/connect/v3/systems/products_controller_spec.rb b/engines/instance_verification/spec/requests/api/connect/v3/systems/products_controller_spec.rb index da9f6bc4a..5d121c8f5 100644 --- a/engines/instance_verification/spec/requests/api/connect/v3/systems/products_controller_spec.rb +++ b/engines/instance_verification/spec/requests/api/connect/v3/systems/products_controller_spec.rb @@ -71,7 +71,7 @@ end context 'when verification provider returns false' do - # let(:plugin_double) { instance_double('InstanceVerification::Providers::Example') } + let(:plugin_double) { instance_double('InstanceVerification::Providers::Example') } before do stub_request(:post, scc_activate_url) @@ -80,8 +80,9 @@ body: { error: 'Unexpected instance verification error has occurred' }.to_json, headers: {} ) - # allow(InstanceVerification::Providers::Example).to receive(:new).and_return(plugin_double) - # allow(plugin_double).to receive(:allowed_extension?).and_return(true) + allow(InstanceVerification::Providers::Example).to receive(:new).and_return(plugin_double) + allow(plugin_double).to receive(:allowed_extension?).and_return(true) + allow(plugin_double).to receive(:instance_valid?).and_return(false) post url, params: payload, headers: headers end @@ -145,8 +146,9 @@ context 'when verification provider returns false' do before do expect(InstanceVerification::Providers::Example).to receive(:new) - .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, instance_data).and_return(plugin_double) + .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, instance_data).and_return(plugin_double).at_least(:once) expect(plugin_double).to receive(:instance_valid?).and_return(false) + allow(plugin_double).to receive(:allowed_extension?).and_return(true) post url, params: payload, headers: headers end @@ -159,8 +161,9 @@ context 'when verification provider raises an unhandled exception' do before do expect(InstanceVerification::Providers::Example).to receive(:new) - .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, instance_data).and_return(plugin_double) + .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, instance_data).and_return(plugin_double).at_least(:once) expect(plugin_double).to receive(:instance_valid?).and_raise('Custom plugin error') + allow(plugin_double).to receive(:allowed_extension?).and_return(true) post url, params: payload, headers: headers end @@ -175,9 +178,9 @@ before do expect(InstanceVerification::Providers::Example).to receive(:new) - .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, instance_data).and_return(plugin_double) + .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, instance_data).and_return(plugin_double).at_least(:once) expect(plugin_double).to receive(:instance_valid?).and_raise(InstanceVerification::Exception, 'Custom plugin error') - + allow(plugin_double).to receive(:allowed_extension?).and_return(true) post url, params: payload, headers: headers end @@ -231,9 +234,9 @@ end before do - allow(InstanceVerification::Providers::Example).to receive(:new) - .with(nil, nil, nil, instance_data).and_return(plugin_double) + allow(InstanceVerification::Providers::Example).to receive(:new).and_return(plugin_double) allow(plugin_double).to receive(:parse_instance_data).and_return({ InstanceId: 'foo' }) + allow(plugin_double).to receive(:allowed_extension?).and_return(true) FactoryBot.create(:subscription, product_classes: product_classes) stub_request(:post, scc_activate_url) @@ -403,7 +406,7 @@ .to_return(status: 201, body: scc_response_body, headers: {}) expect(InstanceVerification).not_to receive(:update_cache).with('127.0.0.1', system.login, product.id) - + allow(plugin_double).to receive(:allowed_extension?).and_return(true) post url, params: payload_no_token, headers: headers end @@ -415,6 +418,10 @@ end context 'when the system is hybrid' do + before do + allow_any_instance_of(InstanceVerification::Providers::Example).to receive(:allowed_extension?).and_return(true) + end + context "when system doesn't have hw_info" do let(:system) { FactoryBot.create(:system, :hybrid) } @@ -448,7 +455,8 @@ context 'when verification provider returns false' do before do expect(InstanceVerification::Providers::Example).to receive(:new) - .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, instance_data).and_return(plugin_double) + .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, instance_data).and_return(plugin_double).at_least(:once) + allow(plugin_double).to receive(:allowed_extension?).and_return(true) expect(plugin_double).to receive(:instance_valid?).and_return(false) post url, params: payload, headers: headers end @@ -462,7 +470,8 @@ context 'when verification provider raises an unhandled exception' do before do expect(InstanceVerification::Providers::Example).to receive(:new) - .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, instance_data).and_return(plugin_double) + .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, instance_data).and_return(plugin_double).at_least(:once) + allow(plugin_double).to receive(:allowed_extension?).and_return(true) expect(plugin_double).to receive(:instance_valid?).and_raise('Custom plugin error') post url, params: payload, headers: headers end From 3e03f2261af9e9d60bc884877229fc6404a2530b Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Tue, 26 Nov 2024 17:07:18 +0000 Subject: [PATCH 19/39] Allowing future SUMA versions in the check --- .../strict_authentication/authentication_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/strict_authentication/app/controllers/strict_authentication/authentication_controller.rb b/engines/strict_authentication/app/controllers/strict_authentication/authentication_controller.rb index ec671999b..a0109ad34 100644 --- a/engines/strict_authentication/app/controllers/strict_authentication/authentication_controller.rb +++ b/engines/strict_authentication/app/controllers/strict_authentication/authentication_controller.rb @@ -45,7 +45,7 @@ def all_allowed_paths(headers) # SUMA 5.0 must have access to SUMA 4.3, 4.2 and so on micro = p.identifier.downcase.include?('sle-micro') instance_id_header = headers.fetch('X-Instance-Identifier', '').casecmp('suse-manager-server').zero? - instance_version_header = headers.fetch('X-Instance-Version', '') == '5.0' + instance_version_header = headers.fetch('X-Instance-Version', '0').split('.')[0] >= '5' manager || (micro && instance_id_header && instance_version_header) end From 6b8f7b2375368cfbf16caa768c0d3213f4a59449 Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Wed, 27 Nov 2024 10:39:11 +0000 Subject: [PATCH 20/39] Simpler and clearer check --- app/controllers/api/connect/v3/systems/products_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/connect/v3/systems/products_controller.rb b/app/controllers/api/connect/v3/systems/products_controller.rb index 62f5d9508..5688cc9b4 100644 --- a/app/controllers/api/connect/v3/systems/products_controller.rb +++ b/app/controllers/api/connect/v3/systems/products_controller.rb @@ -12,7 +12,7 @@ def activate end def show - if @product.identifier.casecmp('sles').zero? + if @product.identifier.casecmp?('sles') # if system has SLE Micro # it should access to SLES products sle_micro = @system.products.any? { |p| p.identifier.downcase.include?('sle-micro') } From a7e6212241ea58dbcfbe40fa930dff0cb72a735a Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Wed, 27 Nov 2024 11:06:08 +0000 Subject: [PATCH 21/39] Fix linter --- .../strict_authentication/authentication_controller.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/engines/strict_authentication/app/controllers/strict_authentication/authentication_controller.rb b/engines/strict_authentication/app/controllers/strict_authentication/authentication_controller.rb index 966475c1b..b3fabfab6 100644 --- a/engines/strict_authentication/app/controllers/strict_authentication/authentication_controller.rb +++ b/engines/strict_authentication/app/controllers/strict_authentication/authentication_controller.rb @@ -28,6 +28,8 @@ def path_allowed?(headers) all_allowed_paths(headers).find { |allowed_path| path =~ /^#{Regexp.escape(allowed_path)}/ } end + # rubocop:disable Metrics/CyclomaticComplexity + # rubocop:disable Metrics/PerceivedComplexity def all_allowed_paths(headers) # return all versions of the same product and arch # (that the system has available with that subscription) @@ -71,5 +73,7 @@ def all_allowed_paths(headers) end allowed_paths end + # rubocop:enable Metrics/CyclomaticComplexity + # rubocop:enable Metrics/PerceivedComplexity end end From a4697936fe2f02dc004468dd4f67a7975a1136ed Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Fri, 29 Nov 2024 10:59:54 +0000 Subject: [PATCH 22/39] Add changes for v2.20 for pubcloud --- package/obs/rmt-server.changes | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package/obs/rmt-server.changes b/package/obs/rmt-server.changes index ed80834ce..cb1e13732 100644 --- a/package/obs/rmt-server.changes +++ b/package/obs/rmt-server.changes @@ -8,6 +8,9 @@ Wed Oct 30 09:01:32 UTC 2024 - Natnael Getahun * rmt-server-pubcloud: * Fix LTSS product verification (bsc#1230154) * Fix activations check when no product info is available (bsc#1230157) + * Fix Azure SCC connection (bsc#1233314) + * Deny access to Azure Basic type images to LTSS + * Allow SLE Micro system to access free SLES repositories (bsc#1230419) ------------------------------------------------------------------- Wed Aug 21 15:28:43 UTC 2024 - Jesús Bermúdez Velázquez From bef95d6ce357a2da9f37ac4049b77655941dc64d Mon Sep 17 00:00:00 2001 From: Natnael Getahun Date: Fri, 29 Nov 2024 14:47:38 +0100 Subject: [PATCH 23/39] Update SCC host configuration to use environment variable --- config/rmt.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/rmt.yml b/config/rmt.yml index 811e44ff2..b1f7e6c6e 100644 --- a/config/rmt.yml +++ b/config/rmt.yml @@ -20,7 +20,7 @@ database_test: database: rmt_test scc: - host: https://scc.suse.com/connect + host: <%= ENV.fetch('SCC_HOST'){ 'https://scc.suse.com/connect' } username: <%= ENV['SCC_USERNAME'] %> password: <%= ENV['SCC_PASSWORD'] %> sync_systems: true From 608defaf0f4d45675219c118aa3a13aa0207850b Mon Sep 17 00:00:00 2001 From: Natnael Getahun Date: Fri, 29 Nov 2024 14:47:38 +0100 Subject: [PATCH 24/39] Update SCC host configuration to use environment variable --- config/rmt.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/rmt.yml b/config/rmt.yml index b1f7e6c6e..6a2df5b5c 100644 --- a/config/rmt.yml +++ b/config/rmt.yml @@ -20,7 +20,7 @@ database_test: database: rmt_test scc: - host: <%= ENV.fetch('SCC_HOST'){ 'https://scc.suse.com/connect' } + host: <%= ENV.fetch('SCC_HOST'){ 'https://scc.suse.com/connect' } %> username: <%= ENV['SCC_USERNAME'] %> password: <%= ENV['SCC_PASSWORD'] %> sync_systems: true From 2728fc73333596f9711e9862d71ab0a900d523f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Berm=C3=BAdez=20Vel=C3=A1zquez?= Date: Mon, 2 Dec 2024 08:33:36 +0000 Subject: [PATCH 25/39] Update package/obs/rmt-server.changes Co-authored-by: Thomas Schmidt --- package/obs/rmt-server.changes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/obs/rmt-server.changes b/package/obs/rmt-server.changes index cb1e13732..cbee6e2ff 100644 --- a/package/obs/rmt-server.changes +++ b/package/obs/rmt-server.changes @@ -9,7 +9,7 @@ Wed Oct 30 09:01:32 UTC 2024 - Natnael Getahun * Fix LTSS product verification (bsc#1230154) * Fix activations check when no product info is available (bsc#1230157) * Fix Azure SCC connection (bsc#1233314) - * Deny access to Azure Basic type images to LTSS + * Deny access of Azure Basic type images to LTSS * Allow SLE Micro system to access free SLES repositories (bsc#1230419) ------------------------------------------------------------------- From acde3707577044a65b12f5910a7bd0a58498bc86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Berm=C3=BAdez=20Vel=C3=A1zquez?= Date: Mon, 2 Dec 2024 08:33:47 +0000 Subject: [PATCH 26/39] Update package/obs/rmt-server.changes Co-authored-by: Thomas Schmidt --- package/obs/rmt-server.changes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/obs/rmt-server.changes b/package/obs/rmt-server.changes index cbee6e2ff..16e598617 100644 --- a/package/obs/rmt-server.changes +++ b/package/obs/rmt-server.changes @@ -10,7 +10,7 @@ Wed Oct 30 09:01:32 UTC 2024 - Natnael Getahun * Fix activations check when no product info is available (bsc#1230157) * Fix Azure SCC connection (bsc#1233314) * Deny access of Azure Basic type images to LTSS - * Allow SLE Micro system to access free SLES repositories (bsc#1230419) + * Allow SLE Micro system to access SLES repositories (bsc#1230419) ------------------------------------------------------------------- Wed Aug 21 15:28:43 UTC 2024 - Jesús Bermúdez Velázquez From 0e430ea67dbf4eba08648a56734b7edabfbc6385 Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Mon, 2 Dec 2024 10:34:30 +0000 Subject: [PATCH 27/39] Fix typo in comment --- .../lib/instance_verification/providers/example.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/instance_verification/lib/instance_verification/providers/example.rb b/engines/instance_verification/lib/instance_verification/providers/example.rb index 393236e4b..ac1523135 100644 --- a/engines/instance_verification/lib/instance_verification/providers/example.rb +++ b/engines/instance_verification/lib/instance_verification/providers/example.rb @@ -52,7 +52,7 @@ def instance_identifier def allowed_extension? # method to check if a product (extension) meet the criteria - # to be acivated on SCC or not, i.e. LTSS in Azure Basic VM + # to be activated on SCC or not, i.e. LTSS in Azure Basic VM true end end From 7002ee6124d5c93c6bbe72c141ba1f35c2551fd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Berm=C3=BAdez=20Vel=C3=A1zquez?= Date: Mon, 2 Dec 2024 12:18:47 +0000 Subject: [PATCH 28/39] Update engines/instance_verification/lib/instance_verification/providers/example.rb Co-authored-by: Thomas Schmidt --- .../lib/instance_verification/providers/example.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/instance_verification/lib/instance_verification/providers/example.rb b/engines/instance_verification/lib/instance_verification/providers/example.rb index ac1523135..e4379c39b 100644 --- a/engines/instance_verification/lib/instance_verification/providers/example.rb +++ b/engines/instance_verification/lib/instance_verification/providers/example.rb @@ -51,7 +51,7 @@ def instance_identifier end def allowed_extension? - # method to check if a product (extension) meet the criteria + # method to check if a product (extension) meets the criteria # to be activated on SCC or not, i.e. LTSS in Azure Basic VM true end From 798ecf9f02d5c2a2c28216f7a4dd7c060a1107f7 Mon Sep 17 00:00:00 2001 From: "parag.jain" Date: Mon, 2 Dec 2024 20:13:17 +0530 Subject: [PATCH 29/39] skip rotation for read Apis --- .../api/connect/base_controller.rb | 8 ++++++++ .../connect/v3/systems/products_controller.rb | 1 + .../connect/v3/systems/systems_controller.rb | 1 + .../connect/v4/systems/products_controller.rb | 1 + app/controllers/application_controller.rb | 6 +++--- .../api/connect/base_controller_spec.rb | 19 +++---------------- 6 files changed, 17 insertions(+), 19 deletions(-) diff --git a/app/controllers/api/connect/base_controller.rb b/app/controllers/api/connect/base_controller.rb index 1fbeaff07..1983fb267 100644 --- a/app/controllers/api/connect/base_controller.rb +++ b/app/controllers/api/connect/base_controller.rb @@ -44,4 +44,12 @@ def authenticate_with_token end end + def system_token_header + headers[SYSTEM_TOKEN_HEADER] = @system.system_token + end + + def refresh_system_token + @system.update(system_token: SecureRandom.uuid) + system_token_header + end end diff --git a/app/controllers/api/connect/v3/systems/products_controller.rb b/app/controllers/api/connect/v3/systems/products_controller.rb index 2545a9e92..fcad5de58 100644 --- a/app/controllers/api/connect/v3/systems/products_controller.rb +++ b/app/controllers/api/connect/v3/systems/products_controller.rb @@ -5,6 +5,7 @@ class Api::Connect::V3::Systems::ProductsController < Api::Connect::BaseControll before_action :check_product_service_and_repositories, only: %i[show activate] before_action :load_subscription, only: %i[activate upgrade] before_action :check_base_product_dependencies, only: %i[activate upgrade show] + after_action :refresh_system_token, only: %i[activate upgrade], if: -> { request.headers.key?(SYSTEM_TOKEN_HEADER) } def activate create_product_activation diff --git a/app/controllers/api/connect/v3/systems/systems_controller.rb b/app/controllers/api/connect/v3/systems/systems_controller.rb index 863557279..d9a17154d 100644 --- a/app/controllers/api/connect/v3/systems/systems_controller.rb +++ b/app/controllers/api/connect/v3/systems/systems_controller.rb @@ -1,6 +1,7 @@ class Api::Connect::V3::Systems::SystemsController < Api::Connect::BaseController before_action :authenticate_system + after_action :refresh_system_token, only: [:update], if: -> { request.headers.key?(SYSTEM_TOKEN_HEADER) } def update if params[:online_at].present? diff --git a/app/controllers/api/connect/v4/systems/products_controller.rb b/app/controllers/api/connect/v4/systems/products_controller.rb index 7237e5a80..c92df74d5 100644 --- a/app/controllers/api/connect/v4/systems/products_controller.rb +++ b/app/controllers/api/connect/v4/systems/products_controller.rb @@ -1,5 +1,6 @@ class Api::Connect::V4::Systems::ProductsController < Api::Connect::V3::Systems::ProductsController + after_action :refresh_system_token, only: %i[synchronize destroy], if: -> { request.headers.key?(SYSTEM_TOKEN_HEADER) } def destroy if @product.base? raise ActionController::TranslatedError.new(N_('The product "%s" is a base product and cannot be deactivated'), @product.name) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 686972895..ba11c3a75 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -21,11 +21,11 @@ def authenticate_system(skip_on_duplicated: false) update_user_agent # If SYSTEM_TOKEN_HEADER is present, RMT assumes the client uses a SUSEConnect version - # that supports this feature. In this case, refresh the token and include it in the response. + # that supports this feature. if system_tokens_enabled? && request.headers.key?(SYSTEM_TOKEN_HEADER) - @system.update(last_seen_at: Time.zone.now, system_token: SecureRandom.uuid) + @system.update(last_seen_at: Time.zone.now) headers[SYSTEM_TOKEN_HEADER] = @system.system_token - # only update last_seen_at each 3 minutes, + # only update last_seen_at each 3 minutes, # so that a system that calls SCC every second doesn't write + lock the database row elsif !@system.last_seen_at || @system.last_seen_at < 3.minutes.ago @system.touch(:last_seen_at) diff --git a/spec/requests/api/connect/base_controller_spec.rb b/spec/requests/api/connect/base_controller_spec.rb index 70ef9aaff..76b1f4b6b 100644 --- a/spec/requests/api/connect/base_controller_spec.rb +++ b/spec/requests/api/connect/base_controller_spec.rb @@ -55,15 +55,6 @@ def require_product end end - shared_examples 'updates the system token' do - it 'updates the system token' do - allow(SecureRandom).to receive(:uuid).and_return(new_system_token) - - expect { get :service, params: { id: 1 } } - .to change { system.reload.system_token } - .from(current_system_token).to(new_system_token) - end - end shared_examples "does not update the old system's token" do it 'does not update the system token' do @@ -74,7 +65,6 @@ def require_product shared_examples 'creates a duplicate system' do it 'creates a new System (duplicate)' do - allow(SecureRandom).to receive(:uuid).and_return(new_system_token) expect { get :service, params: { id: 1 } } .to change { System.get_by_credentials(system.login, system.password).count } @@ -85,7 +75,6 @@ def require_product expect(duplicate_system).not_to eq(system) expect(duplicate_system.activations.count).to eq(system.activations.count) expect(duplicate_system.system_token).not_to eq(system.system_token) - expect(duplicate_system.system_token).to eq(new_system_token) end end @@ -182,8 +171,7 @@ def require_product let(:system) { create(:system, hostname: 'system') } include_examples 'does not create a duplicate system' - include_examples 'updates the system token' - include_examples 'responds with a new token' + include_examples "does not update the old system's token" end context 'when the system has a token and the header matches it' do @@ -193,8 +181,8 @@ def require_product let(:system) { create(:system, hostname: 'system', system_token: current_system_token) } include_examples 'does not create a duplicate system' - include_examples 'updates the system token' - include_examples 'responds with a new token' + include_examples "does not update the old system's token" + end context 'when the system has a token and the header is blank' do @@ -208,7 +196,6 @@ def require_product include_examples "does not update the old system's token" include_examples 'creates a duplicate system' - include_examples 'responds with a new token' end context 'when the system has a token and the header does not match it' do From 3f5a6e8d3d8fcf2b8ff7503e26a37652718642dd Mon Sep 17 00:00:00 2001 From: Thomas Schmidt Date: Wed, 4 Dec 2024 00:09:08 +0100 Subject: [PATCH 30/39] fix rubocop --- app/controllers/application_controller.rb | 2 +- spec/requests/api/connect/base_controller_spec.rb | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index ba11c3a75..bb7504888 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -25,7 +25,7 @@ def authenticate_system(skip_on_duplicated: false) if system_tokens_enabled? && request.headers.key?(SYSTEM_TOKEN_HEADER) @system.update(last_seen_at: Time.zone.now) headers[SYSTEM_TOKEN_HEADER] = @system.system_token - # only update last_seen_at each 3 minutes, + # only update last_seen_at each 3 minutes, # so that a system that calls SCC every second doesn't write + lock the database row elsif !@system.last_seen_at || @system.last_seen_at < 3.minutes.ago @system.touch(:last_seen_at) diff --git a/spec/requests/api/connect/base_controller_spec.rb b/spec/requests/api/connect/base_controller_spec.rb index 76b1f4b6b..8832909ea 100644 --- a/spec/requests/api/connect/base_controller_spec.rb +++ b/spec/requests/api/connect/base_controller_spec.rb @@ -65,7 +65,6 @@ def require_product shared_examples 'creates a duplicate system' do it 'creates a new System (duplicate)' do - expect { get :service, params: { id: 1 } } .to change { System.get_by_credentials(system.login, system.password).count } .by(1) @@ -182,7 +181,6 @@ def require_product include_examples 'does not create a duplicate system' include_examples "does not update the old system's token" - end context 'when the system has a token and the header is blank' do From 59131b6353fd1b2c29a17a4f158e34306dbfcf8f Mon Sep 17 00:00:00 2001 From: "parag.jain" Date: Wed, 4 Dec 2024 12:22:50 +0530 Subject: [PATCH 31/39] add testcases supporting token rotation for write api; add testcases for header token addition in read api --- app/controllers/application_controller.rb | 2 +- .../v3/systems/activations_controller_spec.rb | 23 ++++++ .../v3/systems/products_controller_spec.rb | 55 ++++++++++++++ .../v3/systems/systems_controller_spec.rb | 19 +++++ .../v4/systems/products_controller_spec.rb | 73 +++++++++++++++++++ 5 files changed, 171 insertions(+), 1 deletion(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index bb7504888..63458615a 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -24,7 +24,7 @@ def authenticate_system(skip_on_duplicated: false) # that supports this feature. if system_tokens_enabled? && request.headers.key?(SYSTEM_TOKEN_HEADER) @system.update(last_seen_at: Time.zone.now) - headers[SYSTEM_TOKEN_HEADER] = @system.system_token + system_token_header # only update last_seen_at each 3 minutes, # so that a system that calls SCC every second doesn't write + lock the database row elsif !@system.last_seen_at || @system.last_seen_at < 3.minutes.ago diff --git a/spec/requests/api/connect/v3/systems/activations_controller_spec.rb b/spec/requests/api/connect/v3/systems/activations_controller_spec.rb index a4ff0a562..6a62ee2bd 100644 --- a/spec/requests/api/connect/v3/systems/activations_controller_spec.rb +++ b/spec/requests/api/connect/v3/systems/activations_controller_spec.rb @@ -69,5 +69,28 @@ expect(system.scc_synced_at).to be_nil end end + + context 'system token header' do + context 'when system token header is present in request' do + let(:token_headers) do + authenticated_headers.merge({ 'System-Token' => 'some_token' }) + end + + it 'sets system token in response headers' do + get url, headers: token_headers + expect(response.code).to eq '200' + expect(response.headers).to include('System-Token') + expect(response.headers['System-Token']).not_to be_nil + expect(response.headers['System-Token']).not_to be_empty + end + + it 'does not set system token header if no system token header in request' do + get url, headers: authenticated_headers + + expect(response.code).to eq '200' + expect(response.headers).not_to include('System-Token') + end + end + end end end diff --git a/spec/requests/api/connect/v3/systems/products_controller_spec.rb b/spec/requests/api/connect/v3/systems/products_controller_spec.rb index 457a77d65..9f6c47916 100644 --- a/spec/requests/api/connect/v3/systems/products_controller_spec.rb +++ b/spec/requests/api/connect/v3/systems/products_controller_spec.rb @@ -135,6 +135,26 @@ end end + shared_context 'activate with token in request headers' do + let(:payload) do + { + identifier: product.identifier, + version: product.version, + arch: product.arch, + token: regcode + } + end + + before { post url, headers: { 'System-Token' => 'existing_token' }.merge(headers), params: payload } + subject do + Struct.new(:body, :code, :headers).new( + JSON.parse(response.body, symbolize_names: true), + response.status, + response.headers + ) + end + end + context 'unknown subscription' do include_context 'with subscriptions' let(:regcode) { 'NOT-EXISTING-SUBSCRIPTION' } @@ -173,6 +193,17 @@ expect(activation.product).to eq(product) end end + + context 'token update after activation is success' do + let(:subscription) { create :subscription, :with_products } + let(:product) { subscription.products.first } + let(:regcode) { subscription.regcode } + + include_context 'activate with token in request headers' + its(:code) { is_expected.to eq(201) } + its(:headers) { is_expected.to include('System-Token') } + its(:headers['System-Token']) { is_expected.not_to eq('existing_token') } + end end end @@ -225,6 +256,18 @@ its(:body) { is_expected.to eq(serialized_json) } end + describe 'response header should contain token' do + subject { response } + + let(:token_headers) do + headers.merge({ 'System-Token' => 'some_token' }) + end + + before { get url, headers: token_headers, params: payload } + its(:code) { is_expected.to eq('200') } + its(:headers) { is_expected.to include('System-Token') } + end + describe 'response with "-" in version' do subject { response } @@ -339,6 +382,18 @@ system.reload end + it 'calls refresh_system_token after upgrade action when system token header is present' do + put url, headers: headers.merge('System-Token' => 'test_token'), params: payload + expect(response.code).to eq('201') + expect(response.headers).to include('System-Token') + expect(response.headers['System-Token']).not_to eq('test_token') + end + + it 'No update in token after upgrade action when system token header is absent' do + put url, headers: headers, params: payload + expect(response.code).to eq('201') + expect(response.headers).not_to include('System-Token') + end context 'new product' do its(:code) { is_expected.to eq('201') } its(:body) { is_expected.to eq(serialized_json) } diff --git a/spec/requests/api/connect/v3/systems/systems_controller_spec.rb b/spec/requests/api/connect/v3/systems/systems_controller_spec.rb index 95eede620..91f73d4f4 100644 --- a/spec/requests/api/connect/v3/systems/systems_controller_spec.rb +++ b/spec/requests/api/connect/v3/systems/systems_controller_spec.rb @@ -125,6 +125,25 @@ expect(system.reload.system_information_hash[:user_agent]).to be_nil end end + + context 'response header should contain token' do + let(:headers) { auth_header.merge('System-Token': 'existing-token') } + + it 'contains refreshed token in response' do + update_action + expect(response.headers).to include('System-Token') + expect(response.headers['System-Token']).not_to equal('existing-token') + end + end + + context 'response header should not contain token' do + let(:headers) { auth_header } + + it 'contains refreshed token in response' do + update_action + expect(response.headers).not_to include('System-Token') + end + end end describe '#deregister' do diff --git a/spec/requests/api/connect/v4/systems/products_controller_spec.rb b/spec/requests/api/connect/v4/systems/products_controller_spec.rb index 8bf9a64f4..6f960a941 100644 --- a/spec/requests/api/connect/v4/systems/products_controller_spec.rb +++ b/spec/requests/api/connect/v4/systems/products_controller_spec.rb @@ -140,4 +140,77 @@ end end end + + describe 'system token refresh' do + let(:system) { FactoryBot.create(:system, :with_activated_base_product) } + let(:headers) { auth_header.merge(version_header).merge('System-Token' => 'existing_token') } + + context 'token refresh for destroy action' do + let(:product) { FactoryBot.create(:product, :extension, :with_mirrored_repositories, :activated, system: system) } + let(:payload) { { identifier: product.identifier, version: product.version, arch: product.arch } } + + it 'refreshes system token when System-Token header is present' do + delete connect_systems_products_url, + headers: headers, + params: payload + + expect(response.status).to eq(200) + expect(response.headers).to include('System-Token') + expect(response.headers['System-Token']).not_to eq('existing_token') + end + + it 'does not refresh token when System-Token header is absent' do + headers_without_token = auth_header.merge(version_header) + expect_any_instance_of(described_class).not_to receive(:refresh_system_token) + + delete connect_systems_products_url, + headers: headers_without_token, + params: payload + + expect(response.status).to eq(200) + expect(response.headers).not_to include('System-Token') + end + end + + context 'token refresh for synchronize action' do + let(:path) { '/connect/systems/products/synchronize' } + + it 'refreshes system token when System-Token header is present' do + params = system.products.map do |product| + { + identifier: product.identifier, + version: product.version, + arch: product.arch, + release_type: product.release_type + } + end + post path, + params: { products: params }, + headers: headers + + expect(response.status).to eq(200) + expect(response.headers).to include('System-Token') + expect(response.headers['System-Token']).not_to eq('existing_token') + end + + it 'does not refresh token when System-Token header is absent' do + headers_without_token = auth_header.merge(version_header) + + params = system.products.map do |product| + { + identifier: product.identifier, + version: product.version, + arch: product.arch, + release_type: product.release_type + } + end + post path, + params: { products: params }, + headers: headers_without_token + + expect(response.status).to eq(200) + expect(response.headers).not_to include('System-Token') + end + end + end end From c0be53cd3e758fa7ba9b026d6d5e64c332f81c31 Mon Sep 17 00:00:00 2001 From: "parag.jain" Date: Wed, 4 Dec 2024 15:41:57 +0530 Subject: [PATCH 32/39] add system token enable check --- app/controllers/api/connect/base_controller.rb | 6 ++++-- .../api/connect/v4/systems/products_controller.rb | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/controllers/api/connect/base_controller.rb b/app/controllers/api/connect/base_controller.rb index 1983fb267..84de46574 100644 --- a/app/controllers/api/connect/base_controller.rb +++ b/app/controllers/api/connect/base_controller.rb @@ -49,7 +49,9 @@ def system_token_header end def refresh_system_token - @system.update(system_token: SecureRandom.uuid) - system_token_header + if system_tokens_enabled? + @system.update(system_token: SecureRandom.uuid) + system_token_header + end end end diff --git a/app/controllers/api/connect/v4/systems/products_controller.rb b/app/controllers/api/connect/v4/systems/products_controller.rb index c92df74d5..d4c87adfc 100644 --- a/app/controllers/api/connect/v4/systems/products_controller.rb +++ b/app/controllers/api/connect/v4/systems/products_controller.rb @@ -1,6 +1,6 @@ class Api::Connect::V4::Systems::ProductsController < Api::Connect::V3::Systems::ProductsController - after_action :refresh_system_token, only: %i[synchronize destroy], if: -> { request.headers.key?(SYSTEM_TOKEN_HEADER) } + after_action :refresh_system_token, only: %i[activate upgrade synchronize destroy], if: -> { request.headers.key?(SYSTEM_TOKEN_HEADER) } def destroy if @product.base? raise ActionController::TranslatedError.new(N_('The product "%s" is a base product and cannot be deactivated'), @product.name) From 07961c69f578ae92e5b5163d2a8a1221753d65cf Mon Sep 17 00:00:00 2001 From: "parag.jain" Date: Thu, 5 Dec 2024 18:26:05 +0530 Subject: [PATCH 33/39] Add entry to .changes file for skipping system token rotation in read-only APIs --- package/obs/rmt-server.changes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/obs/rmt-server.changes b/package/obs/rmt-server.changes index ed80834ce..6e048aba3 100644 --- a/package/obs/rmt-server.changes +++ b/package/obs/rmt-server.changes @@ -8,7 +8,7 @@ Wed Oct 30 09:01:32 UTC 2024 - Natnael Getahun * rmt-server-pubcloud: * Fix LTSS product verification (bsc#1230154) * Fix activations check when no product info is available (bsc#1230157) - + * Skip system token rotation in read-only APIs ------------------------------------------------------------------- Wed Aug 21 15:28:43 UTC 2024 - Jesús Bermúdez Velázquez From 992c0a0b23121a70f82af8b26ffebdd7cb797ac2 Mon Sep 17 00:00:00 2001 From: "parag.jain" Date: Wed, 11 Dec 2024 13:02:53 +0530 Subject: [PATCH 34/39] Refactor SUSE repo cleanup and local path generation logic supporting akamai url --- app/models/repository.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 6a7719aa2..6fedd7945 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -23,14 +23,16 @@ class Repository < ApplicationRecord class << self def remove_suse_repos_without_tokens! - where(auth_token: nil).where('external_url LIKE ?', 'https://updates.suse.com%').delete_all + where(auth_token: nil) + .where("external_url LIKE 'https://updates.suse.com%' OR external_url LIKE 'https://dl.suse.com%'") + .delete_all end # Mangles remote repo URL to make a nicer local path, see specs for examples def make_local_path(url) uri = URI(url) path = uri.path.to_s - path.gsub!(%r{^/repo}, '') if (uri.hostname == 'updates.suse.com') + path.gsub!(%r{^/repo}, '') if (uri.hostname == 'updates.suse.com' || uri.hostname == 'dl.suse.com') (path == '') ? '/' : path end From caa983103853f35b895d95dd7290c8b0bbc41834 Mon Sep 17 00:00:00 2001 From: "parag.jain" Date: Thu, 12 Dec 2024 17:50:37 +0530 Subject: [PATCH 35/39] remove function remove_suse_repos_without_tokens!; --- app/models/repository.rb | 10 ++-------- lib/rmt/scc.rb | 6 ------ spec/lib/rmt/scc_spec.rb | 4 ---- 3 files changed, 2 insertions(+), 18 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 6fedd7945..ff09674e0 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -21,18 +21,12 @@ class Repository < ApplicationRecord before_destroy :ensure_destroy_possible class << self - - def remove_suse_repos_without_tokens! - where(auth_token: nil) - .where("external_url LIKE 'https://updates.suse.com%' OR external_url LIKE 'https://dl.suse.com%'") - .delete_all - end - # Mangles remote repo URL to make a nicer local path, see specs for examples def make_local_path(url) uri = URI(url) path = uri.path.to_s - path.gsub!(%r{^/repo}, '') if (uri.hostname == 'updates.suse.com' || uri.hostname == 'dl.suse.com') + # drop '/repo' from SLE11 paths, to avoid double /repo/repo in local storage path. + path.gsub!(%r{^/repo/\$RCE/}, '/$RCE/') (path == '') ? '/' : path end diff --git a/lib/rmt/scc.rb b/lib/rmt/scc.rb index 59fccdf2a..63cbe5106 100644 --- a/lib/rmt/scc.rb +++ b/lib/rmt/scc.rb @@ -24,9 +24,6 @@ def sync data.each { |item| migration_paths(item) } update_repositories(scc_api_client.list_repositories) - - Repository.remove_suse_repos_without_tokens! - update_subscriptions(scc_api_client.list_subscriptions) end @@ -68,9 +65,6 @@ def import(path) data.each { |item| migration_paths(item) } update_repositories(JSON.parse(File.read(File.join(path, 'organizations_repositories.json')), symbolize_names: true)) - - Repository.remove_suse_repos_without_tokens! - update_subscriptions(JSON.parse(File.read(File.join(path, 'organizations_subscriptions.json')), symbolize_names: true)) end diff --git a/spec/lib/rmt/scc_spec.rb b/spec/lib/rmt/scc_spec.rb index 802cf1c8a..4b62370fb 100644 --- a/spec/lib/rmt/scc_spec.rb +++ b/spec/lib/rmt/scc_spec.rb @@ -290,10 +290,6 @@ def scc expect { suse_repo_with_token.reload }.not_to raise_error end - it 'SUSE repos without auth_tokens are removed' do - expect { suse_repo_without_token.reload }.to raise_error(ActiveRecord::RecordNotFound) - end - it 'other repos without auth_tokens persist' do expect { other_repo_without_token.reload }.not_to raise_error end From d81ee4b82a8591e2f56203236418116524a6fb74 Mon Sep 17 00:00:00 2001 From: "parag.jain" Date: Mon, 16 Dec 2024 14:08:21 +0530 Subject: [PATCH 36/39] Refactor SUSE repo cleanup and local path generation logic supporting akamai url --- app/models/repository.rb | 5 +++++ lib/rmt/scc.rb | 6 ++++++ spec/lib/rmt/scc_spec.rb | 7 ++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index ff09674e0..347ec5548 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -21,6 +21,11 @@ class Repository < ApplicationRecord before_destroy :ensure_destroy_possible class << self + + def remove_suse_repos_without_tokens! + where(auth_token: nil).where("external_url LIKE '%.suse.com%'").where(installer_updates: 0).delete_all + end + # Mangles remote repo URL to make a nicer local path, see specs for examples def make_local_path(url) uri = URI(url) diff --git a/lib/rmt/scc.rb b/lib/rmt/scc.rb index 63cbe5106..59fccdf2a 100644 --- a/lib/rmt/scc.rb +++ b/lib/rmt/scc.rb @@ -24,6 +24,9 @@ def sync data.each { |item| migration_paths(item) } update_repositories(scc_api_client.list_repositories) + + Repository.remove_suse_repos_without_tokens! + update_subscriptions(scc_api_client.list_subscriptions) end @@ -65,6 +68,9 @@ def import(path) data.each { |item| migration_paths(item) } update_repositories(JSON.parse(File.read(File.join(path, 'organizations_repositories.json')), symbolize_names: true)) + + Repository.remove_suse_repos_without_tokens! + update_subscriptions(JSON.parse(File.read(File.join(path, 'organizations_subscriptions.json')), symbolize_names: true)) end diff --git a/spec/lib/rmt/scc_spec.rb b/spec/lib/rmt/scc_spec.rb index 496730e56..a62077d00 100644 --- a/spec/lib/rmt/scc_spec.rb +++ b/spec/lib/rmt/scc_spec.rb @@ -261,7 +261,8 @@ :repository, :with_products, auth_token: nil, - external_url: 'https://example.com/repos/not/updates.suse.com/' + external_url: 'https://installer-updates.suse.com/repos/not/updates', + installer_updates: true ) end @@ -290,6 +291,10 @@ def scc expect { suse_repo_with_token.reload }.not_to raise_error end + it 'SUSE repos without auth_tokens are removed' do + expect { suse_repo_without_token.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + it 'other repos without auth_tokens persist' do expect { other_repo_without_token.reload }.not_to raise_error end From 3503590a1b8e7128b707fd32e15dc1eba985d687 Mon Sep 17 00:00:00 2001 From: "parag.jain" Date: Mon, 16 Dec 2024 16:41:35 +0530 Subject: [PATCH 37/39] add check for custom repos --- app/models/repository.rb | 2 +- spec/lib/rmt/scc_spec.rb | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 347ec5548..c65c602cd 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -23,7 +23,7 @@ class Repository < ApplicationRecord class << self def remove_suse_repos_without_tokens! - where(auth_token: nil).where("external_url LIKE '%.suse.com%'").where(installer_updates: 0).delete_all + where(auth_token: nil).where("external_url LIKE '%.suse.com%'").where(installer_updates: 0).where.not(scc_id: nil).delete_all end # Mangles remote repo URL to make a nicer local path, see specs for examples diff --git a/spec/lib/rmt/scc_spec.rb b/spec/lib/rmt/scc_spec.rb index a62077d00..f1e3b9d61 100644 --- a/spec/lib/rmt/scc_spec.rb +++ b/spec/lib/rmt/scc_spec.rb @@ -265,6 +265,16 @@ installer_updates: true ) end + let!(:custom_repo) do + FactoryBot.create( + :repository, + :with_products, + auth_token: nil, + external_url: 'http://customer.com/stuff.suse.com/x86', + installer_updates: false, + scc_id: nil + ) + end before do # to prevent 'does not implement' verifying doubles error @@ -298,6 +308,10 @@ def scc it 'other repos without auth_tokens persist' do expect { other_repo_without_token.reload }.not_to raise_error end + + it 'custom repos without auth_tokens persist' do + expect { custom_repo.reload }.not_to raise_error + end end describe '#export' do From 4aa1e0e1151a1939430e781adfb82c1872ff3de2 Mon Sep 17 00:00:00 2001 From: "parag.jain" Date: Mon, 16 Dec 2024 18:48:16 +0530 Subject: [PATCH 38/39] Enable RMT to handle the new dl.suse.com CDN domain --- package/obs/rmt-server.changes | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package/obs/rmt-server.changes b/package/obs/rmt-server.changes index f587e6685..2cc735f92 100644 --- a/package/obs/rmt-server.changes +++ b/package/obs/rmt-server.changes @@ -11,7 +11,8 @@ Wed Oct 30 09:01:32 UTC 2024 - Natnael Getahun * Fix Azure SCC connection (bsc#1233314) * Deny access of Azure Basic type images to LTSS * Allow SLE Micro system to access SLES repositories (bsc#1230419) - * Skip system token rotation in read-only APIs + * Skip system token rotation in read-only APIs + * Enable RMT to handle the new dl.suse.com CDN domain. ------------------------------------------------------------------- Wed Aug 21 15:28:43 UTC 2024 - Jesús Bermúdez Velázquez From 192969892576986b04353fffa0909ce87cc2225c Mon Sep 17 00:00:00 2001 From: Thomas Schmidt Date: Mon, 16 Dec 2024 16:24:07 +0100 Subject: [PATCH 39/39] add bugzilla reference --- package/obs/rmt-server.changes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/obs/rmt-server.changes b/package/obs/rmt-server.changes index 2cc735f92..c84e3dbf6 100644 --- a/package/obs/rmt-server.changes +++ b/package/obs/rmt-server.changes @@ -12,7 +12,7 @@ Wed Oct 30 09:01:32 UTC 2024 - Natnael Getahun * Deny access of Azure Basic type images to LTSS * Allow SLE Micro system to access SLES repositories (bsc#1230419) * Skip system token rotation in read-only APIs - * Enable RMT to handle the new dl.suse.com CDN domain. + * Enable RMT to handle the new dl.suse.com CDN domain (bsc#1234641) ------------------------------------------------------------------- Wed Aug 21 15:28:43 UTC 2024 - Jesús Bermúdez Velázquez