ci(ios): refresh scoped production push signing profile
TestFlight / Build and upload (push) Successful in 1m45s
TestFlight / Build and upload (push) Successful in 1m45s
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
require_relative 'refresh_push_profile'
|
||||
|
||||
default_platform(:ios)
|
||||
|
||||
platform :ios do
|
||||
@@ -5,6 +7,7 @@ platform :ios do
|
||||
lane :beta do
|
||||
setup_ci
|
||||
|
||||
SybilPushProfile.run
|
||||
match(type: "appstore")
|
||||
|
||||
tag = ENV.fetch("GITHUB_REF_NAME")
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user