diff --git a/match/lib/match/runner.rb b/match/lib/match/runner.rb index a5fe81c9ce3..7151dd78ec1 100644 --- a/match/lib/match/runner.rb +++ b/match/lib/match/runner.rb @@ -68,14 +68,14 @@ def run(params) # then in the future address the root cause of https://github.com/fastlane/fastlane/issues/11324 app_identifiers = app_identifiers.flatten.uniq - # Cache bundle ids, certificates, profiles, and devices. - self.cache = Portal::Cache.build( - params: params, - bundle_id_identifiers: app_identifiers - ) - - # Verify the App ID (as we don't want 'match' to fail at a later point) if spaceship + # Cache bundle ids, certificates, profiles, and devices. + self.cache = Portal::Cache.build( + params: params, + bundle_id_identifiers: app_identifiers + ) + + # Verify the App ID (as we don't want 'match' to fail at a later point) app_identifiers.each do |app_identifier| spaceship.bundle_identifier_exists(username: params[:username], app_identifier: app_identifier, cached_bundle_ids: self.cache.bundle_ids) end @@ -247,16 +247,19 @@ def fetch_provisioning_profile(params: nil, profile_type:, certificate_id: nil, stored_profile_path = profiles.last force = params[:force] - portal_profile = self.cache.portal_profile(stored_profile_path: stored_profile_path, keychain_path: keychain_path) if stored_profile_path + if spaceship + # check if profile needs to be updated only if not in readonly mode + portal_profile = self.cache.portal_profile(stored_profile_path: stored_profile_path, keychain_path: keychain_path) if stored_profile_path - if params[:force_for_new_devices] - force ||= ProfileIncludes.should_force_include_all_devices?(params: params, portal_profile: portal_profile, cached_devices: self.cache.devices) - end + if params[:force_for_new_devices] + force ||= ProfileIncludes.should_force_include_all_devices?(params: params, portal_profile: portal_profile, cached_devices: self.cache.devices) + end - if params[:include_all_certificates] - # Clearing specified certificate id which will prevent a profile being created with only one certificate - certificate_id = nil - force ||= ProfileIncludes.should_force_include_all_certificates?(params: params, portal_profile: portal_profile, cached_certificates: self.cache.certificates) + if params[:include_all_certificates] + # Clearing specified certificate id which will prevent a profile being created with only one certificate + certificate_id = nil + force ||= ProfileIncludes.should_force_include_all_certificates?(params: params, portal_profile: portal_profile, cached_certificates: self.cache.certificates) + end end is_new_profile_created = false diff --git a/match/spec/runner_spec.rb b/match/spec/runner_spec.rb index 8ab30aa37b8..c23c297e8ed 100644 --- a/match/spec/runner_spec.rb +++ b/match/spec/runner_spec.rb @@ -1,21 +1,14 @@ +require_relative 'spec_helper' + describe Match do describe Match::Runner do let(:keychain) { 'login.keychain' } - let(:fake_cache) { double('fake_cache') } before do allow(ENV).to receive(:[]).and_call_original allow(ENV).to receive(:[]).with('MATCH_KEYCHAIN_NAME').and_return(keychain) allow(ENV).to receive(:[]).with('MATCH_KEYCHAIN_PASSWORD').and_return(nil) - allow(Match::Portal::Cache).to receive(:new).and_return(fake_cache) - allow(fake_cache).to receive(:bundle_ids).and_return(nil) - allow(fake_cache).to receive(:certificates).and_return(nil) - allow(fake_cache).to receive(:profiles).and_return(nil) - allow(fake_cache).to receive(:devices).and_return(nil) - allow(fake_cache).to receive(:portal_profile).and_return(nil) - allow(fake_cache).to receive(:reset_certificates) - # There is another test ENV.delete('FASTLANE_TEAM_ID') ENV.delete('FASTLANE_TEAM_NAME') @@ -48,6 +41,8 @@ keychain_path = FastlaneCore::Helper.keychain_path("login.keychain") # can be .keychain or .keychain-db destination = File.expand_path("~/Library/MobileDevice/Provisioning Profiles/98264c6b-5151-4349-8d0f-66691e48ae35.mobileprovision") + fake_cache = create_fake_cache + fake_storage = "fake_storage" expect(Match::Storage::GitStorage).to receive(:configure).with({ git_url: git_url, @@ -117,6 +112,8 @@ username: "flapple@something.com" } + create_fake_cache + config = FastlaneCore::Configuration.create(Match::Options.available_options, values) repo_dir = "./match/spec/fixtures/existing" cert_path = "./match/spec/fixtures/existing/certs/distribution/E7P4EE896K.cer" @@ -195,6 +192,8 @@ cert_path = "./match/spec/fixtures/existing/certs/distribution/E7P4EE896K.cer" key_path = "./match/spec/fixtures/existing/certs/distribution/E7P4EE896K.p12" + create_fake_cache + fake_storage = "fake_storage" expect(Match::Storage::GitStorage).to receive(:configure).with({ git_url: git_url, @@ -233,6 +232,58 @@ end.to raise_error("Your certificate 'E7P4EE896K.cer' is not valid, please check end date and renew it if necessary") end + it "installs profiles in read-only mode", requires_security: true do + # GIVEN + + # Downloaded and decrypted storage location. + repo_dir = "./match/spec/fixtures/existing" + # Valid cert and key + stored_valid_cert_path = "#{repo_dir}/certs/distribution/E7P4EE896K.cer" + stored_valid_profile_path = "#{repo_dir}/profiles/appstore/AppStore_tools.fastlane.app.mobileprovision" + + # match options + match_test_options = { + readonly: true # Current test suite. + } + match_config = create_match_config_with_git_storage(extra_values: match_test_options) + + # EXPECTATIONS + + # Ensure cache is not used. + create_fake_cache(allow_usage: false) + + # Storage + fake_storage = create_fake_storage(match_config: match_config, repo_dir: repo_dir) + # Ensure no changes in storage are made. + expect(fake_storage).not_to receive(:save_changes!) + + # Encryption + fake_encryption = create_fake_encryption(storage: fake_storage) + # Ensure there are no new files to encrypt. + expect(fake_encryption).not_to receive(:encrypt_files) + + # Utils + # Ensure match validates stored certificate. + expect(Match::Utils).to receive(:is_cert_valid?).with(stored_valid_cert_path).and_return(true) + + # Certificates + # Ensure a new certificate is not generated. + expect(Match::Generator).not_to receive(:generate_certificate).with(match_config, :distribution, fake_storage.working_directory, specific_cert_type: nil) + + # Profiles + begin # Ensure profiles are installed, but not validated. + keychain_path = FastlaneCore::Helper.keychain_path("login.keychain") + expect(FastlaneCore::ProvisioningProfile).to receive(:install).with(stored_valid_profile_path, keychain_path) + expect(Match::Generator).not_to receive(:generate_provisioning_profile) + end + + # WHEN + Match::Runner.new.run(match_config) + + # THEN + # Rely on expectations defined above. + end + it "skips provisioning profiles when skip_provisioning_profiles set to true", requires_security: true do git_url = "https://github.com/fastlane/fastlane/tree/master/certificates" values = { @@ -250,6 +301,8 @@ keychain_path = FastlaneCore::Helper.keychain_path("login.keychain") # can be .keychain or .keychain-db destination = File.expand_path("~/Library/MobileDevice/Provisioning Profiles/98264c6b-5151-4349-8d0f-66691e48ae35.mobileprovision") + create_fake_cache + fake_storage = "fake_storage" expect(Match::Storage::GitStorage).to receive(:configure).with({ git_url: git_url, diff --git a/match/spec/spec_helper.rb b/match/spec/spec_helper.rb index ee8a149a430..616094a53e3 100644 --- a/match/spec/spec_helper.rb +++ b/match/spec/spec_helper.rb @@ -8,3 +8,113 @@ def before_each_match ENV["DELIVER_USER"] = "flapple@krausefx.com" ENV["DELIVER_PASSWORD"] = "so_secret" end + +def create_fake_storage(match_config:, repo_dir:) + fake_storage = "fake_storage" + expect(Match::Storage::GitStorage).to receive(:configure).with({ + git_url: match_config[:git_url], + shallow_clone: true, + skip_docs: false, + git_branch: "master", + git_full_name: nil, + git_user_email: nil, + clone_branch_directly: false, + git_basic_authorization: nil, + git_bearer_authorization: nil, + git_private_key: nil, + type: match_config[:type], + platform: match_config[:platform] + }).and_return(fake_storage) + + allow(fake_storage).to receive(:git_url).and_return(match_config[:git_url]) + allow(fake_storage).to receive(:working_directory).and_return(repo_dir) + allow(fake_storage).to receive(:prefixed_working_directory).and_return(repo_dir) + + # Ensure match downloads storage. + expect(fake_storage).to receive(:download).and_return(nil) + # Ensure match clears changes after completion. + expect(fake_storage).to receive(:clear_changes).and_return(nil) + + return fake_storage +end + +def default_app_identifier + "tools.fastlane.app" +end + +def default_provisioning_type + "appstore" +end + +def default_git_url + "https://github.com/fastlane/fastlane/tree/master/certificates" +end + +def default_username + "flapple@something.com" +end + +def create_match_config_with_git_storage(extra_values: {}, git_url: nil, app_identifier: nil, type: nil, username: nil) + values = { + app_identifier: app_identifier || default_app_identifier, + type: type || default_provisioning_type, + git_url: git_url || default_git_url, + username: username || default_username, + shallow_clone: true + } + + extra_values.each do |k, v| + values[k] = v + end + + match_config = FastlaneCore::Configuration.create(Match::Options.available_options, values) + + return match_config +end + +def create_fake_encryption(storage:) + fake_encryption = "fake_encryption" + expect(Match::Encryption::OpenSSL).to receive(:new).with(keychain_name: storage.git_url, working_directory: storage.working_directory).and_return(fake_encryption) + + # Ensure files from storage are decrypted. + expect(fake_encryption).to receive(:decrypt_files).and_return(nil) + + return fake_encryption +end + +def create_fake_spaceship_ensure + spaceship_ensure = "spaceship" + + allow(Match::SpaceshipEnsure).to receive(:new).and_return(spaceship_ensure) + + # Ensure app identifiers are validated. + expect(spaceship_ensure).to receive(:bundle_identifier_exists).and_return(true) + + return spaceship_ensure +end + +def create_fake_cache(allow_usage: true) + fake_cache = 'fake_cache' + + allow(Match::Portal::Cache).to receive(:new).and_return(fake_cache) + + if allow_usage + allow(fake_cache).to receive(:bundle_ids).and_return(nil) + allow(fake_cache).to receive(:certificates).and_return(nil) + allow(fake_cache).to receive(:profiles).and_return(nil) + allow(fake_cache).to receive(:devices).and_return(nil) + allow(fake_cache).to receive(:portal_profile).and_return(nil) + allow(fake_cache).to receive(:reset_certificates) + else + expect(Match::Portal::Cache).not_to receive(:new) + + expect(fake_cache).not_to receive(:bundle_ids) + expect(fake_cache).not_to receive(:certificates) + expect(fake_cache).not_to receive(:profiles) + expect(fake_cache).not_to receive(:devices) + expect(fake_cache).not_to receive(:portal_profile) + expect(fake_cache).not_to receive(:reset_certificates) + end + + fake_cache +end