diff --git a/ios/fastlane/Fastfile b/ios/fastlane/Fastfile index e3f7117..e87321b 100644 --- a/ios/fastlane/Fastfile +++ b/ios/fastlane/Fastfile @@ -1,5 +1,3 @@ -require_relative 'refresh_push_profile' - default_platform(:ios) platform :ios do @@ -7,8 +5,7 @@ platform :ios do lane :beta do setup_ci - SybilPushProfile.run - match(type: "appstore") + match(type: "appstore", readonly: true) tag = ENV.fetch("GITHUB_REF_NAME") version = tag[%r{\Arelease/ios/v(\d+\.\d+\.\d+)\z}, 1] diff --git a/ios/fastlane/refresh_push_profile.rb b/ios/fastlane/refresh_push_profile.rb deleted file mode 100644 index 3fcad28..0000000 --- a/ios/fastlane/refresh_push_profile.rb +++ /dev/null @@ -1,75 +0,0 @@ -# One app-scoped bootstrap for the already-regenerated Sybil distribution profile. -# Invoked inside the existing CI job so MATCH_PASSWORD never leaves that job. -require 'match' -require 'match/encryption' -require 'cfpropertylist' -require 'digest' -require 'fileutils' -require 'open3' -require 'tmpdir' - -module SybilPushProfile - PROFILE = File.expand_path('~/.config/sybil-release-signing/Sybil_AppStore_CI.mobileprovision') - REPOSITORY = 'https://code.buzzert.dev/buzzert/fastlane-match.git' - TARGET = 'profiles/appstore/AppStore_net.buzzert.sybil2.mobileprovision' - UUID = '6ca8c49d-ca89-4b9f-8ae8-a0e33fafd19c' - CERTIFICATE = '6B74B268C4761720FB2051D01D8BB3E47B55D9F5' - - def self.run - return unless File.exist?(PROFILE) - stage = 'profile validation' - file = File.lstat(PROFILE) - parent = File.stat(File.dirname(PROFILE)) - raise unless file.file? && !file.symlink? && file.uid == Process.uid && (file.mode & 0o077).zero? - raise unless parent.uid == Process.uid && (parent.mode & 0o077).zero? - xml, _, status = Open3.capture3('/usr/bin/security', 'cms', '-D', '-i', PROFILE) - raise unless status.success? - profile = CFPropertyList.native_types(CFPropertyList::List.new(data: xml).value) - entitlements = profile.fetch('Entitlements') - raise unless profile['UUID'] == UUID && profile['Name'] == 'Sybil AppStore CI' - raise unless profile['TeamIdentifier'] == ['DQQH5H6GBD'] - raise unless entitlements['application-identifier'] == 'DQQH5H6GBD.net.buzzert.sybil2' - raise unless entitlements['aps-environment'] == 'production' && entitlements['get-task-allow'] == false - raise unless profile.fetch('DeveloperCertificates').any? { |c| Digest::SHA1.hexdigest(c).upcase == CERTIFICATE } - raise unless profile.fetch('ExpirationDate') > Time.now - plaintext = File.binread(PROFILE) - password = ENV.fetch('MATCH_PASSWORD') - authorization = ENV.fetch('MATCH_GIT_BASIC_AUTHORIZATION') - raise if password.empty? || authorization.empty? || authorization.match?(/[\r\n]/) - git_env = { 'GIT_TERMINAL_PROMPT' => '0', 'GIT_CONFIG_COUNT' => '1', - 'GIT_CONFIG_KEY_0' => 'http.https://code.buzzert.dev/.extraheader', - 'GIT_CONFIG_VALUE_0' => "Authorization: Basic #{authorization}" } - git = lambda do |*args| - out, _, result = Open3.capture3(git_env, 'git', *args) - raise unless result.success? - out - end - stage = 'encrypted profile refresh' - Dir.mktmpdir('sybil-profile-') do |temp| - File.chmod(0o700, temp) - repo = File.join(temp, 'match') - git.call('clone', '--quiet', '--single-branch', REPOSITORY, repo) - target = File.join(repo, TARGET) - raise unless File.file?(target) && !File.symlink?(target) - crypto = Match::Encryption::MatchDataEncryption.new - current = crypto.decrypt(base64encoded_encrypted: File.read(target), password: password) - if current == plaintext - puts 'Sybil production Push profile is already current in match.' - return - end - encrypted = crypto.encrypt(data: plaintext, password: password, version: 2) - raise unless crypto.decrypt(base64encoded_encrypted: encrypted, password: password) == plaintext - File.write(target, encrypted) - changed = git.call('-C', repo, 'diff', '--name-only').lines.map(&:strip) - raise unless changed == [TARGET] - git.call('-C', repo, 'add', '--', TARGET) - git.call('-C', repo, '-c', 'user.name=Sybil CI', '-c', 'user.email=james@magahern.com', - 'commit', '--quiet', '-m', 'signing: refresh Sybil production Push profile') - stage = 'normal signing-repository push' - git.call('-C', repo, 'push', 'origin', 'HEAD') - puts 'Updated only the encrypted Sybil production Push profile in match.' - end - rescue StandardError - abort "Sybil signing profile refresh failed at #{stage}; credential details withheld." - end -end