diff --git a/README.md b/README.md index 9ea8f0e..9c07dcc 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,7 @@ steps: | `api_key_path` | Local path or remote URL to the private key (p8 file) for App Store Connect API. This overrides the Bitrise-managed API connection, only set this input if you want to control the API connection on a step-level. Most of the time it's easier to set up the connection on the App Settings page on Bitrise. The input value can be a file path (eg. `$TMPDIR/private_key.p8`) or an HTTPS URL. This input only takes effect if the other two connection override inputs are set too (`api_key_id`, `api_key_issuer_id`). | | | | `api_key_id` | Private key ID used for App Store Connect authentication. This overrides the Bitrise-managed API connection, only set this input if you want to control the API connection on a step-level. Most of the time it's easier to set up the connection on the App Settings page on Bitrise. This input only takes effect if the other two connection override inputs are set too (`api_key_path`, `api_key_issuer_id`). | | | | `api_key_issuer_id` | Private key issuer ID used for App Store Connect authentication. This overrides the Bitrise-managed API connection, only set this input if you want to control the API connection on a step-level. Most of the time it's easier to set up the connection on the App Settings page on Bitrise. This input only takes effect if the other two connection override inputs are set too (`api_key_path`, `api_key_id`). | | | +| `api_key_enterprise_account` | Indicates if the account is an enterprise type. This overrides the Bitrise-managed API connection, only set this input if you know you have an enterprise account. | required | `no` | | `verbose_log` | If this input is set, the Step will print additional logs for debugging. | required | `no` | diff --git a/go.mod b/go.mod index ebf372b..b7cab4d 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/bitrise-io/go-utils v1.0.12 github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.23 github.com/bitrise-io/go-xcode v1.1.1 - github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.48 + github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.50 howett.net/plist v1.0.0 ) diff --git a/go.sum b/go.sum index 11d9881..af9572b 100644 --- a/go.sum +++ b/go.sum @@ -13,8 +13,8 @@ github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.23 h1:Dfh4nyZPuEtilBisidejqxBrkx9 github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.23/go.mod h1:3XUplo0dOWc3DqT2XA2SeHToDSg7+j1y1HTHibT2H68= github.com/bitrise-io/go-xcode v1.1.1 h1:Krfa8iYZZWdLBuH7AXbufFZwL+Pys7etqvd8+Ehdwt8= github.com/bitrise-io/go-xcode v1.1.1/go.mod h1:9OwsvrhZ4A2JxHVoEY7CPcABAKA+OE7FQqFfBfvbFuY= -github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.48 h1:nsd41UsIGZrPy94tlFxoDCfH2I19A9buPOA/cLgucjA= -github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.48/go.mod h1:KpxSPrRLgY0fscSajOyO/5h7MhapsqnSJr17oXEaPsg= +github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.50 h1:vh3miMo4lZb5fz8D1Tca0AerRv2hO3gZS4R5nEeSXKg= +github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.50/go.mod h1:KpxSPrRLgY0fscSajOyO/5h7MhapsqnSJr17oXEaPsg= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/main.go b/main.go index e3b5e20..6ca4616 100644 --- a/main.go +++ b/main.go @@ -10,15 +10,14 @@ import ( "github.com/bitrise-io/go-steputils/output" "github.com/bitrise-io/go-steputils/v2/stepconf" v1command "github.com/bitrise-io/go-utils/command" - "github.com/bitrise-io/go-utils/fileutil" v1log "github.com/bitrise-io/go-utils/log" "github.com/bitrise-io/go-utils/pathutil" "github.com/bitrise-io/go-utils/retry" "github.com/bitrise-io/go-utils/v2/command" "github.com/bitrise-io/go-utils/v2/env" + "github.com/bitrise-io/go-utils/v2/fileutil" "github.com/bitrise-io/go-utils/v2/log" "github.com/bitrise-io/go-utils/v2/retryhttp" - "github.com/bitrise-io/go-xcode/devportalservice" "github.com/bitrise-io/go-xcode/models" "github.com/bitrise-io/go-xcode/profileutil" "github.com/bitrise-io/go-xcode/utility" @@ -28,6 +27,7 @@ import ( "github.com/bitrise-io/go-xcode/v2/autocodesign/localcodesignasset" "github.com/bitrise-io/go-xcode/v2/autocodesign/profiledownloader" "github.com/bitrise-io/go-xcode/v2/codesign" + "github.com/bitrise-io/go-xcode/v2/devportalservice" "github.com/bitrise-io/go-xcode/v2/xcarchive" "github.com/bitrise-io/go-xcode/xcodebuild" "howett.net/plist" @@ -67,9 +67,10 @@ type Inputs struct { ManageVersionAndBuildNumber bool `env:"manage_version_and_build_number"` ExportOptionsPlistContent string `env:"export_options_plist_content"` // App Store Connect connection override - APIKeyPath stepconf.Secret `env:"api_key_path"` - APIKeyID string `env:"api_key_id"` - APIKeyIssuerID string `env:"api_key_issuer_id"` + APIKeyPath stepconf.Secret `env:"api_key_path"` + APIKeyID string `env:"api_key_id"` + APIKeyIssuerID string `env:"api_key_issuer_id"` + APIKeyEnterpriseAccount bool `env:"api_key_enterprise_account,opt[yes,no]"` // Debugging VerboseLog bool `env:"verbose_log,opt[yes,no]"` // Output export @@ -110,6 +111,11 @@ type Step struct { commandFactory command.Factory inputParser stepconf.InputParser logger log.Logger + fileManager fileutil.FileManager +} + +func NewStep(commandFactory command.Factory, inputParser stepconf.InputParser, logger log.Logger, fileManager fileutil.FileManager) Step { + return Step{commandFactory: commandFactory, inputParser: inputParser, logger: logger, fileManager: fileManager} } func (s Step) ProcessInputs() (Config, error) { @@ -212,7 +218,7 @@ func (s Step) createCodesignManager(inputs Inputs, xcodeMajorVersion int) (codes archive := codesign.NewArchive(a) var serviceConnection *devportalservice.AppleDeveloperConnection = nil - devPortalClientFactory := devportalclient.NewFactory(s.logger) + devPortalClientFactory := devportalclient.NewFactory(s.logger, s.fileManager) if inputs.BuildURL != "" && inputs.BuildAPIToken != "" { if serviceConnection, err = devPortalClientFactory.CreateBitriseConnection(inputs.BuildURL, string(inputs.BuildAPIToken)); err != nil { return codesign.Manager{}, err @@ -220,9 +226,10 @@ func (s Step) createCodesignManager(inputs Inputs, xcodeMajorVersion int) (codes } connectionInputs := codesign.ConnectionOverrideInputs{ - APIKeyPath: inputs.APIKeyPath, - APIKeyID: inputs.APIKeyID, - APIKeyIssuerID: inputs.APIKeyIssuerID, + APIKeyPath: inputs.APIKeyPath, + APIKeyID: inputs.APIKeyID, + APIKeyIssuerID: inputs.APIKeyIssuerID, + APIKeyEnterpriseAccount: inputs.APIKeyEnterpriseAccount, } appleAuthCredentials, err := codesign.SelectConnectionCredentials(authType, serviceConnection, connectionInputs, s.logger) @@ -344,7 +351,7 @@ func (s Step) Run(opts Config) (RunOut, error) { s.logger.Printf("Export options content provided, using it:") fmt.Println(opts.ExportOptionsPlistContent) - if err := fileutil.WriteStringToFile(exportOptionsPath, opts.ExportOptionsPlistContent); err != nil { + if err := s.fileManager.Write(exportOptionsPath, opts.ExportOptionsPlistContent, 0700); err != nil { return RunOut{}, fmt.Errorf("failed to write export options to file, error: %s", err) } } else { @@ -355,7 +362,7 @@ func (s Step) Run(opts Config) (RunOut, error) { s.logger.Printf("\ngenerated export options content:\n%s", exportOptionsContent) - if err := fileutil.WriteStringToFile(exportOptionsPath, exportOptionsContent); err != nil { + if err := s.fileManager.Write(exportOptionsPath, exportOptionsContent, 0700); err != nil { return RunOut{}, fmt.Errorf("failed to write export options to file, error: %s", err) } @@ -470,11 +477,7 @@ func (s Step) ExportOutput(opts ExportOpts) error { func RunStep() error { envRepository := env.NewRepository() - step := Step{ - commandFactory: command.NewFactory(envRepository), - inputParser: stepconf.NewInputParser(envRepository), - logger: log.NewLogger(), - } + step := NewStep(command.NewFactory(envRepository), stepconf.NewInputParser(envRepository), log.NewLogger(), fileutil.NewFileManager()) config, err := step.ProcessInputs() if err != nil { diff --git a/step.yml b/step.yml index 3737325..2b1fa07 100755 --- a/step.yml +++ b/step.yml @@ -252,7 +252,6 @@ inputs: on a step-level. Most of the time it's easier to set up the connection on the App Settings page on Bitrise. The input value can be a file path (eg. `$TMPDIR/private_key.p8`) or an HTTPS URL. This input only takes effect if the other two connection override inputs are set too (`api_key_id`, `api_key_issuer_id`). - is_required: false - api_key_id: opts: @@ -264,7 +263,6 @@ inputs: This overrides the Bitrise-managed API connection, only set this input if you want to control the API connection on a step-level. Most of the time it's easier to set up the connection on the App Settings page on Bitrise. This input only takes effect if the other two connection override inputs are set too (`api_key_path`, `api_key_issuer_id`). - is_required: false - api_key_issuer_id: opts: @@ -276,7 +274,19 @@ inputs: This overrides the Bitrise-managed API connection, only set this input if you want to control the API connection on a step-level. Most of the time it's easier to set up the connection on the App Settings page on Bitrise. This input only takes effect if the other two connection override inputs are set too (`api_key_path`, `api_key_id`). - is_required: false + +- api_key_enterprise_account: "no" + opts: + category: App Store Connect connection override + title: App Store Connect API enterprise account + summary: Indicates if the account is an enterprise type. This overrides the Bitrise-managed API connection. + description: |- + Indicates if the account is an enterprise type. + This overrides the Bitrise-managed API connection, only set this input if you know you have an enterprise account. + value_options: + - "yes" + - "no" + is_required: true # Debugging diff --git a/vendor/github.com/bitrise-io/go-utils/v2/fileutil/fileutil.go b/vendor/github.com/bitrise-io/go-utils/v2/fileutil/fileutil.go new file mode 100644 index 0000000..4b2bfa5 --- /dev/null +++ b/vendor/github.com/bitrise-io/go-utils/v2/fileutil/fileutil.go @@ -0,0 +1,105 @@ +package fileutil + +import ( + "errors" + "io" + "io/fs" + "os" + "path/filepath" +) + +// FileManager ... +type FileManager interface { + Open(path string) (*os.File, error) + OpenReaderIfExists(path string) (io.Reader, error) + ReadDirEntryNames(path string) ([]string, error) + Remove(path string) error + RemoveAll(path string) error + Write(path string, value string, perm os.FileMode) error + WriteBytes(path string, value []byte) error + FileSizeInBytes(pth string) (int64, error) +} + +type fileManager struct { +} + +// NewFileManager ... +func NewFileManager() FileManager { + return fileManager{} +} + +// ReadDirEntryNames reads the named directory using os.ReadDir and returns the dir entries' names. +func (fileManager) ReadDirEntryNames(path string) ([]string, error) { + entries, err := os.ReadDir(path) + if err != nil { + return nil, err + } + var names []string + for _, entry := range entries { + names = append(names, entry.Name()) + } + return names, nil +} + +// Open ... +func (fileManager) Open(path string) (*os.File, error) { + return os.Open(path) +} + +// OpenReaderIfExists opens the named file using os.Open and returns an io.Reader. +// An ErrNotExist error is absorbed and the returned io.Reader will be nil, +// other errors from os.Open are returned as is. +func (fileManager) OpenReaderIfExists(path string) (io.Reader, error) { + file, err := os.Open(path) + if errors.Is(err, fs.ErrNotExist) { + return nil, nil + } + if err != nil { + return nil, err + } + return file, nil +} + +// Remove ... +func (fileManager) Remove(path string) error { + return os.Remove(path) +} + +// RemoveAll ... +func (fileManager) RemoveAll(path string) error { + return os.RemoveAll(path) +} + +// Write ... +func (f fileManager) Write(path string, value string, mode os.FileMode) error { + if err := f.ensureSavePath(path); err != nil { + return err + } + if err := os.WriteFile(path, []byte(value), mode); err != nil { + return err + } + return os.Chmod(path, mode) +} + +func (fileManager) ensureSavePath(savePath string) error { + dirPath := filepath.Dir(savePath) + return os.MkdirAll(dirPath, 0700) +} + +// WriteBytes ... +func (f fileManager) WriteBytes(path string, value []byte) error { + return os.WriteFile(path, value, 0600) +} + +// FileSizeInBytes checks if the provided path exists and return with the file size (bytes) using os.Lstat. +func (fileManager) FileSizeInBytes(pth string) (int64, error) { + if pth == "" { + return 0, errors.New("No path provided") + } + fileInf, err := os.Stat(pth) + if err != nil { + return 0, err + } + + return fileInf.Size(), nil +} diff --git a/vendor/github.com/bitrise-io/go-xcode/appleauth/auth_source.go b/vendor/github.com/bitrise-io/go-xcode/appleauth/auth_source.go deleted file mode 100644 index 3d8c971..0000000 --- a/vendor/github.com/bitrise-io/go-xcode/appleauth/auth_source.go +++ /dev/null @@ -1,188 +0,0 @@ -package appleauth - -import ( - "fmt" - "time" - - "github.com/bitrise-io/go-xcode/devportalservice" -) - -// Source returns a specific kind (Apple ID/API Key) Apple authentication data from a specific source (Bitrise Apple Developer Connection, Step inputs) -type Source interface { - Fetch(connection *devportalservice.AppleDeveloperConnection, inputs Inputs) (*Credentials, error) - Description() string -} - -// ConnectionAPIKeySource provides API Key from Bitrise Apple Developer Connection -type ConnectionAPIKeySource struct{} - -// InputAPIKeySource provides API Key from Step inputs -type InputAPIKeySource struct{} - -// ConnectionAppleIDSource provides Apple ID from Bitrise Apple Developer Connection -type ConnectionAppleIDSource struct{} - -// InputAppleIDSource provides Apple ID from Step inputs -type InputAppleIDSource struct{} - -// ConnectionAppleIDFastlaneSource provides Apple ID from Bitrise Apple Developer Connection, includes Fastlane specific session -type ConnectionAppleIDFastlaneSource struct{} - -// InputAppleIDFastlaneSource provides Apple ID from Step inputs, includes Fastlane specific session -type InputAppleIDFastlaneSource struct{} - -// Description ... -func (*ConnectionAPIKeySource) Description() string { - return "Bitrise Apple Developer Connection with API key found" -} - -// Fetch ... -func (*ConnectionAPIKeySource) Fetch(conn *devportalservice.AppleDeveloperConnection, inputs Inputs) (*Credentials, error) { - if conn == nil || conn.APIKeyConnection == nil { // Not configured - return nil, nil - } - - return &Credentials{ - APIKey: conn.APIKeyConnection, - }, nil -} - -// - -// Description ... -func (*InputAPIKeySource) Description() string { - return "Inputs with API key authentication found" -} - -// Fetch ... -func (*InputAPIKeySource) Fetch(conn *devportalservice.AppleDeveloperConnection, inputs Inputs) (*Credentials, error) { - if inputs.APIKeyPath == "" { // Not configured - return nil, nil - } - - privateKey, keyID, err := fetchPrivateKey(inputs.APIKeyPath) - if err != nil { - return nil, fmt.Errorf("could not fetch private key (%s) specified as input: %v", inputs.APIKeyPath, err) - } - if len(privateKey) == 0 { - return nil, fmt.Errorf("private key (%s) is empty", inputs.APIKeyPath) - } - - return &Credentials{ - APIKey: &devportalservice.APIKeyConnection{ - IssuerID: inputs.APIIssuer, - KeyID: keyID, - PrivateKey: string(privateKey), - }, - }, nil -} - -// - -// Description ... -func (*ConnectionAppleIDSource) Description() string { - return "Bitrise Apple Developer Connection with Apple ID found." -} - -// Fetch ... -func (*ConnectionAppleIDSource) Fetch(conn *devportalservice.AppleDeveloperConnection, inputs Inputs) (*Credentials, error) { - if conn == nil || conn.AppleIDConnection == nil { // No Apple ID configured - return nil, nil - } - - return &Credentials{ - AppleID: &AppleID{ - Username: conn.AppleIDConnection.AppleID, - Password: conn.AppleIDConnection.Password, - Session: "", - AppSpecificPassword: appSpecificPasswordFavouringConnection(conn.AppleIDConnection, inputs.AppSpecificPassword), - }, - }, nil -} - -// - -// Description ... -func (*InputAppleIDSource) Description() string { - return "Inputs with Apple ID authentication found." -} - -// Fetch ... -func (*InputAppleIDSource) Fetch(conn *devportalservice.AppleDeveloperConnection, inputs Inputs) (*Credentials, error) { - if inputs.Username == "" { // Not configured - return nil, nil - } - - return &Credentials{ - AppleID: &AppleID{ - Username: inputs.Username, - Password: inputs.Password, - AppSpecificPassword: inputs.AppSpecificPassword, - }, - }, nil -} - -// - -// Description ... -func (*ConnectionAppleIDFastlaneSource) Description() string { - return "Bitrise Apple Developer Connection with Apple ID found." -} - -// Fetch ... -func (*ConnectionAppleIDFastlaneSource) Fetch(conn *devportalservice.AppleDeveloperConnection, inputs Inputs) (*Credentials, error) { - if conn == nil || conn.AppleIDConnection == nil { // No Apple ID configured - return nil, nil - } - - appleIDConn := conn.AppleIDConnection - if appleIDConn.SessionExpiryDate != nil && appleIDConn.SessionExpiryDate.Before(time.Now()) { - return nil, fmt.Errorf("2FA session saved in Bitrise Developer Connection is expired, was valid until %s", appleIDConn.SessionExpiryDate.String()) - } - session, err := appleIDConn.FastlaneLoginSession() - if err != nil { - return nil, fmt.Errorf("could not prepare Fastlane session cookie object: %v", err) - } - - return &Credentials{ - AppleID: &AppleID{ - Username: conn.AppleIDConnection.AppleID, - Password: conn.AppleIDConnection.Password, - Session: session, - AppSpecificPassword: appSpecificPasswordFavouringConnection(conn.AppleIDConnection, inputs.AppSpecificPassword), - }, - }, nil -} - -// - -// Description ... -func (*InputAppleIDFastlaneSource) Description() string { - return "Inputs with Apple ID authentication found. This method does not support TFA enabled Apple IDs." -} - -// Fetch ... -func (*InputAppleIDFastlaneSource) Fetch(conn *devportalservice.AppleDeveloperConnection, inputs Inputs) (*Credentials, error) { - if inputs.Username == "" { // Not configured - return nil, nil - } - - return &Credentials{ - AppleID: &AppleID{ - Username: inputs.Username, - Password: inputs.Password, - AppSpecificPassword: inputs.AppSpecificPassword, - }, - }, nil -} - -func appSpecificPasswordFavouringConnection(conn *devportalservice.AppleIDConnection, passwordFromInput string) string { - appSpecificPassword := passwordFromInput - - // AppSpecifcPassword from the connection overwrites the one from the input - if conn != nil && conn.AppSpecificPassword != "" { - appSpecificPassword = conn.AppSpecificPassword - } - - return appSpecificPassword -} diff --git a/vendor/github.com/bitrise-io/go-xcode/appleauth/fetch.go b/vendor/github.com/bitrise-io/go-xcode/appleauth/fetch.go deleted file mode 100644 index 91027fe..0000000 --- a/vendor/github.com/bitrise-io/go-xcode/appleauth/fetch.go +++ /dev/null @@ -1,60 +0,0 @@ -package appleauth - -import ( - "fmt" - - "github.com/bitrise-io/go-utils/log" - "github.com/bitrise-io/go-xcode/devportalservice" -) - -// Credentials contains either Apple ID or APIKey auth info -type Credentials struct { - AppleID *AppleID - APIKey *devportalservice.APIKeyConnection -} - -// AppleID contains Apple ID auth info -// -// Without 2FA: -// Required: username, password -// With 2FA: -// Required: username, password, appSpecificPassword -// session (Only for Fastlane, set as FASTLANE_SESSION) -// -// As Fastlane spaceship uses: -// - iTMSTransporter: it requires Username + Password (or App-specific password with 2FA) -// - TunesAPI: it requires Username + Password (+ 2FA session with 2FA) -type AppleID struct { - Username, Password string - Session, AppSpecificPassword string -} - -// MissingAuthConfigError is returned in case no usable Apple App Store Connect / Developer Portal authenticaion is found -type MissingAuthConfigError struct { -} - -func (*MissingAuthConfigError) Error() string { - return "no credentials provided" -} - -// Select return valid Apple ID or API Key based authentication data, from the provided Bitrise Apple Developer Connection or Inputs -// authSources: required, array of checked sources (in order, the first set one will be used) -// for example: []AppleAuthSource{&SourceConnectionAPIKey{}, &SourceConnectionAppleID{}, &SourceInputAPIKey{}, &SourceInputAppleID{}} -// inputs: optional, user provided inputs that are not centrally managed (by setting up connections) -func Select(conn *devportalservice.AppleDeveloperConnection, authSources []Source, inputs Inputs) (Credentials, error) { - for _, source := range authSources { - auth, err := source.Fetch(conn, inputs) - if err != nil { - return Credentials{}, err - } - - if auth != nil { - fmt.Println() - log.Infof("%s", source.Description()) - - return *auth, nil - } - } - - return Credentials{}, &MissingAuthConfigError{} -} diff --git a/vendor/github.com/bitrise-io/go-xcode/appleauth/inputs.go b/vendor/github.com/bitrise-io/go-xcode/appleauth/inputs.go deleted file mode 100644 index 34fbaea..0000000 --- a/vendor/github.com/bitrise-io/go-xcode/appleauth/inputs.go +++ /dev/null @@ -1,57 +0,0 @@ -package appleauth - -import ( - "fmt" - "strings" - - "github.com/bitrise-io/go-utils/log" -) - -// Inputs is Apple Service authentication configuration provided by end user -type Inputs struct { - // Apple ID - Username, Password, AppSpecificPassword string - // API key (JWT) - APIIssuer, APIKeyPath string -} - -// Validate trims extra spaces and checks input grouping -func (cfg *Inputs) Validate() error { - cfg.APIIssuer = strings.TrimSpace(cfg.APIIssuer) - cfg.APIKeyPath = strings.TrimSpace(cfg.APIKeyPath) - cfg.Username = strings.TrimSpace(cfg.Username) - cfg.AppSpecificPassword = strings.TrimSpace(cfg.AppSpecificPassword) - var ( - isAPIKeyAuthType = (cfg.APIKeyPath != "" || cfg.APIIssuer != "") - isAppleIDAuthType = (cfg.AppSpecificPassword != "" || cfg.Username != "" || cfg.Password != "") - ) - - switch { - case isAppleIDAuthType && isAPIKeyAuthType: - log.Warnf("Either provide Apple ID, Password (and App-specific password if available) OR API Key Path and API Issuer") - return fmt.Errorf("both Apple ID and API key related configuration provided, but only one of them expected") - - case isAppleIDAuthType: - if cfg.AppSpecificPassword != "" { - // App Specific Password provided, assuming 2FA is enabled. - // In this case 2FA session is required, configured Bitrise account connection required, this contains username+password - break - } - if cfg.Username == "" { - return fmt.Errorf("no Apple Service Apple ID provided") - } - if cfg.Password == "" { - return fmt.Errorf("no Apple Service Password provided") - } - - case isAPIKeyAuthType: - if cfg.APIIssuer == "" { - return fmt.Errorf("no Apple Service API Issuer provided") - } - if cfg.APIKeyPath == "" { - return fmt.Errorf("no Apple Service API Key Path provided") - } - } - - return nil -} diff --git a/vendor/github.com/bitrise-io/go-xcode/appleauth/key_helper.go b/vendor/github.com/bitrise-io/go-xcode/appleauth/key_helper.go deleted file mode 100644 index 9c53b7a..0000000 --- a/vendor/github.com/bitrise-io/go-xcode/appleauth/key_helper.go +++ /dev/null @@ -1,44 +0,0 @@ -package appleauth - -import ( - "net/http" - "net/url" - "os" - "path/filepath" - "regexp" - - "github.com/bitrise-io/go-steputils/input" - "github.com/bitrise-io/go-utils/filedownloader" -) - -func fetchPrivateKey(privateKeyURL string) ([]byte, string, error) { - fileURL, err := url.Parse(privateKeyURL) - if err != nil { - return nil, "", err - } - - // Download or load local file - filedownloader := filedownloader.New(http.DefaultClient) - fileProvider := input.NewFileProvider(filedownloader) - localFile, err := fileProvider.LocalPath(fileURL.String()) - if err != nil { - return nil, "", err - } - key, err := os.ReadFile(localFile) - if err != nil { - return nil, "", err - } - - return key, getKeyID(fileURL), nil -} - -func getKeyID(u *url.URL) string { - var keyID = "Bitrise" // as default if no ID found in file name - - // get the ID of the key from the file - if matches := regexp.MustCompile(`AuthKey_(.+)\.p8`).FindStringSubmatch(filepath.Base(u.Path)); len(matches) == 2 { - keyID = matches[1] - } - - return keyID -} diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/autocodesign.go b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/autocodesign.go index f00e0a4..8cd6351 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/autocodesign.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/autocodesign.go @@ -11,9 +11,9 @@ import ( "github.com/bitrise-io/go-utils/log" "github.com/bitrise-io/go-xcode/certificateutil" - "github.com/bitrise-io/go-xcode/devportalservice" "github.com/bitrise-io/go-xcode/profileutil" "github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect" + "github.com/bitrise-io/go-xcode/v2/devportalservice" "github.com/bitrise-io/go-xcode/xcodeproject/serialized" ) diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devices.go b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devices.go index 6995a7b..d8ab518 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devices.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devices.go @@ -5,8 +5,8 @@ import ( "fmt" "github.com/bitrise-io/go-utils/log" - "github.com/bitrise-io/go-xcode/devportalservice" "github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect" + "github.com/bitrise-io/go-xcode/v2/devportalservice" ) // EnsureTestDevices fetches devices from Apple, and register missing devices. diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect/appstoreconnect.go b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect/appstoreconnect.go index 73d9a38..106fc70 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect/appstoreconnect.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect/appstoreconnect.go @@ -12,6 +12,7 @@ import ( "net/http" "net/url" "reflect" + "strings" "time" "github.com/bitrise-io/go-utils/httputil" @@ -23,7 +24,12 @@ import ( ) const ( - baseURL = "https://api.appstoreconnect.apple.com/" + clientBaseURL = "https://api.appstoreconnect.apple.com/" + tokenAudience = "appstoreconnect-v1" + + clientBaseEnterpiseURL = "https://api.enterprise.developer.apple.com/" + tokenEnterpriseAudience = "apple-developer-enterprise-v1" + apiVersion = "v1" ) @@ -52,6 +58,7 @@ type Client struct { keyID string issuerID string privateKeyContent []byte + audience string token *jwt.Token signedToken string @@ -83,8 +90,15 @@ func NewRetryableHTTPClient() *http.Client { } // NewClient creates a new client -func NewClient(httpClient HTTPClient, keyID, issuerID string, privateKey []byte) *Client { - baseURL, err := url.Parse(baseURL) +func NewClient(httpClient HTTPClient, keyID, issuerID string, privateKey []byte, isEnterpise bool) *Client { + targetURL := clientBaseURL + targetAudience := tokenAudience + if isEnterpise { + targetURL = clientBaseEnterpiseURL + targetAudience = tokenEnterpriseAudience + } + + baseURL, err := url.Parse(targetURL) if err != nil { panic("invalid api base url: " + err.Error()) } @@ -93,6 +107,7 @@ func NewClient(httpClient HTTPClient, keyID, issuerID string, privateKey []byte) keyID: keyID, issuerID: issuerID, privateKeyContent: privateKey, + audience: targetAudience, client: httpClient, BaseURL: baseURL, @@ -126,7 +141,7 @@ func (c *Client) ensureSignedToken() (string, error) { log.Debugf("Generating JWT token") } - c.token = createToken(c.keyID, c.issuerID) + c.token = createToken(c.keyID, c.issuerID, c.audience) var err error if c.signedToken, err = signToken(c.token, c.privateKeyContent); err != nil { return "", err @@ -134,9 +149,21 @@ func (c *Client) ensureSignedToken() (string, error) { return c.signedToken, nil } +// NewRequestWithRelationshipURL ... +func (c *Client) NewRequestWithRelationshipURL(method, endpoint string, body interface{}) (*http.Request, error) { + endpoint = strings.TrimPrefix(endpoint, c.BaseURL.String()+apiVersion+"/") + + return c.NewRequest(method, endpoint, body) +} + // NewRequest creates a new http.Request func (c *Client) NewRequest(method, endpoint string, body interface{}) (*http.Request, error) { endpoint = apiVersion + "/" + endpoint + + return c.newRequest(method, endpoint, body) +} + +func (c *Client) newRequest(method, endpoint string, body interface{}) (*http.Request, error) { u, err := c.BaseURL.Parse(endpoint) if err != nil { return nil, fmt.Errorf("parsing endpoint failed: %v", err) diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect/bundleids.go b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect/bundleids.go index b720924..0b4c598 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect/bundleids.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect/bundleids.go @@ -2,7 +2,6 @@ package appstoreconnect import ( "net/http" - "strings" ) // BundleIDsEndpoint ... @@ -125,8 +124,7 @@ func (s ProvisioningService) CreateBundleID(body BundleIDCreateRequest) (*Bundle // BundleID ... func (s ProvisioningService) BundleID(relationshipLink string) (*BundleIDResponse, error) { - endpoint := strings.TrimPrefix(relationshipLink, baseURL+apiVersion) - req, err := s.client.NewRequest(http.MethodGet, endpoint, nil) + req, err := s.client.NewRequestWithRelationshipURL(http.MethodGet, relationshipLink, nil) if err != nil { return nil, err } diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect/capabilities.go b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect/capabilities.go index 0082d4f..1d800cd 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect/capabilities.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect/capabilities.go @@ -2,7 +2,6 @@ package appstoreconnect import ( "net/http" - "strings" ) // BundleIDCapabilitiesEndpoint ... @@ -262,8 +261,7 @@ func (s ProvisioningService) UpdateCapability(id string, body BundleIDCapability // Capabilities ... func (s ProvisioningService) Capabilities(relationshipLink string) (*BundleIDCapabilitiesResponse, error) { - endpoint := strings.TrimPrefix(relationshipLink, baseURL+apiVersion) - req, err := s.client.NewRequest(http.MethodGet, endpoint, nil) + req, err := s.client.NewRequestWithRelationshipURL(http.MethodGet, relationshipLink, nil) if err != nil { return nil, err } diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect/certificates.go b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect/certificates.go index e64ce5e..875df54 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect/certificates.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect/certificates.go @@ -3,7 +3,6 @@ package appstoreconnect import ( "fmt" "net/http" - "strings" ) // CertificatesEndpoint ... @@ -108,8 +107,7 @@ func (s ProvisioningService) Certificates(relationshipLink string, opt *PagingOp return nil, err } - endpoint := strings.TrimPrefix(u, baseURL+apiVersion) - req, err := s.client.NewRequest(http.MethodGet, endpoint, nil) + req, err := s.client.NewRequestWithRelationshipURL(http.MethodGet, u, nil) if err != nil { return nil, err } diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect/devices.go b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect/devices.go index 50f28cc..f95a68a 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect/devices.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect/devices.go @@ -2,7 +2,6 @@ package appstoreconnect import ( "net/http" - "strings" ) // DevicesEndpoint ... @@ -145,8 +144,7 @@ func (s ProvisioningService) Devices(relationshipLink string, opt *PagingOptions return nil, err } - endpoint := strings.TrimPrefix(u, baseURL+apiVersion) - req, err := s.client.NewRequest(http.MethodGet, endpoint, nil) + req, err := s.client.NewRequestWithRelationshipURL(http.MethodGet, u, nil) if err != nil { return nil, err } diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect/jwt.go b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect/jwt.go index ce66577..818fdeb 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect/jwt.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect/jwt.go @@ -31,11 +31,11 @@ func signToken(token *jwt.Token, privateKeyContent []byte) (string, error) { } // createToken creates a jwt.Token for the Apple API -func createToken(keyID string, issuerID string) *jwt.Token { +func createToken(keyID string, issuerID string, audience string) *jwt.Token { payload := claims{ IssuerID: issuerID, Expiration: time.Now().Add(jwtDuration).Unix(), - Audience: "appstoreconnect-v1", + Audience: audience, } // registers headers: alg = ES256 and typ = JWT diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect/profiles.go b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect/profiles.go index 322d4e2..87e8774 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect/profiles.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect/profiles.go @@ -2,7 +2,6 @@ package appstoreconnect import ( "net/http" - "strings" "github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/time" "github.com/bitrise-io/go-xcode/xcodeproject/serialized" @@ -286,8 +285,7 @@ func (s ProvisioningService) Profiles(relationshipLink string, opt *PagingOption return nil, err } - endpoint := strings.TrimPrefix(u, baseURL+apiVersion) - req, err := s.client.NewRequest(http.MethodGet, endpoint, nil) + req, err := s.client.NewRequestWithRelationshipURL(http.MethodGet, u, nil) if err != nil { return nil, err } diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnectclient/devices.go b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnectclient/devices.go index 233456c..bd99492 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnectclient/devices.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnectclient/devices.go @@ -5,8 +5,8 @@ import ( "fmt" "net/http" - "github.com/bitrise-io/go-xcode/devportalservice" "github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect" + "github.com/bitrise-io/go-xcode/v2/devportalservice" ) // DeviceClient ... diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/devportalclient.go b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/devportalclient.go index 8d01bc2..4d17042 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/devportalclient.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/devportalclient.go @@ -9,13 +9,13 @@ import ( "github.com/bitrise-io/go-utils/retry" "github.com/bitrise-io/go-utils/v2/command" "github.com/bitrise-io/go-utils/v2/env" + "github.com/bitrise-io/go-utils/v2/fileutil" "github.com/bitrise-io/go-utils/v2/log" - "github.com/bitrise-io/go-xcode/appleauth" - "github.com/bitrise-io/go-xcode/devportalservice" "github.com/bitrise-io/go-xcode/v2/autocodesign" "github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect" "github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnectclient" "github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/spaceship" + "github.com/bitrise-io/go-xcode/v2/devportalservice" ) const ( @@ -27,13 +27,15 @@ Read more: https://devcenter.bitrise.io/getting-started/configuring-bitrise-step // Factory ... type Factory struct { - logger log.Logger + logger log.Logger + filemanager fileutil.FileManager } // NewFactory ... -func NewFactory(logger log.Logger) Factory { +func NewFactory(logger log.Logger, filemanager fileutil.FileManager) Factory { return Factory{ - logger: logger, + logger: logger, + filemanager: filemanager, } } @@ -41,7 +43,7 @@ func NewFactory(logger log.Logger) Factory { func (f Factory) CreateBitriseConnection(buildURL, buildAPIToken string) (*devportalservice.AppleDeveloperConnection, error) { f.logger.Println() f.logger.Infof("Fetching Apple Service connection") - connectionProvider := devportalservice.NewBitriseClient(retry.NewHTTPClient().StandardClient(), buildURL, buildAPIToken) + connectionProvider := devportalservice.NewBitriseClient(f.logger, f.filemanager, retry.NewHTTPClient().StandardClient(), buildURL, buildAPIToken) conn, err := connectionProvider.GetAppleDeveloperConnection() if err != nil { if networkErr, ok := err.(devportalservice.NetworkError); ok && networkErr.Status == http.StatusUnauthorized { @@ -68,13 +70,13 @@ func (f Factory) CreateBitriseConnection(buildURL, buildAPIToken string) (*devpo } // Create ... -func (f Factory) Create(credentials appleauth.Credentials, teamID string) (autocodesign.DevPortalClient, error) { +func (f Factory) Create(credentials devportalservice.Credentials, teamID string) (autocodesign.DevPortalClient, error) { f.logger.Println() f.logger.Infof("Initializing Developer Portal client") var devportalClient autocodesign.DevPortalClient if credentials.APIKey != nil { httpClient := appstoreconnect.NewRetryableHTTPClient() - client := appstoreconnect.NewClient(httpClient, credentials.APIKey.KeyID, credentials.APIKey.IssuerID, []byte(credentials.APIKey.PrivateKey)) + client := appstoreconnect.NewClient(httpClient, credentials.APIKey.KeyID, credentials.APIKey.IssuerID, []byte(credentials.APIKey.PrivateKey), credentials.APIKey.EnterpriseAccount) client.EnableDebugLogs = false // Turn off client debug logs including HTTP call debug logs devportalClient = appstoreconnectclient.NewAPIDevPortalClient(client) f.logger.Debugf("App Store Connect API client created with base URL: %s", client.BaseURL) diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/spaceship/devices.go b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/spaceship/devices.go index 2e7d223..e80b416 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/spaceship/devices.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/spaceship/devices.go @@ -7,8 +7,8 @@ import ( "strings" "github.com/bitrise-io/go-utils/log" - "github.com/bitrise-io/go-xcode/devportalservice" "github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect" + "github.com/bitrise-io/go-xcode/v2/devportalservice" ) // DeviceClient ... diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/spaceship/spaceship.go b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/spaceship/spaceship.go index 80f11df..8ebf07b 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/spaceship/spaceship.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/spaceship/spaceship.go @@ -20,8 +20,8 @@ import ( "github.com/bitrise-io/go-steputils/v2/ruby" "github.com/bitrise-io/go-utils/log" "github.com/bitrise-io/go-utils/v2/command" - "github.com/bitrise-io/go-xcode/appleauth" "github.com/bitrise-io/go-xcode/v2/autocodesign" + "github.com/bitrise-io/go-xcode/v2/devportalservice" ) //go:embed spaceship @@ -29,15 +29,16 @@ var spaceship embed.FS // Client ... type Client struct { - workDir string - authConfig appleauth.AppleID - teamID string + workDir string + authConfig devportalservice.AppleID + teamID string + isNoSleepRetry bool cmdFactory ruby.CommandFactory } // NewClient ... -func NewClient(authConfig appleauth.AppleID, teamID string, cmdFactory ruby.CommandFactory) (*Client, error) { +func NewClient(authConfig devportalservice.AppleID, teamID string, cmdFactory ruby.CommandFactory) (*Client, error) { dir, err := prepareSpaceship(cmdFactory) if err != nil { return nil, err @@ -116,7 +117,9 @@ func (c *Client) runSpaceshipCommand(subCommand string, opts ...string) (string, log.Debugf(spaceshipErr.Error()) log.TWarnf("spaceship command failed with a retryable error, retrying (%d. attempt)...", i) - time.Sleep(time.Duration(i) * time.Minute) + if !c.isNoSleepRetry { + time.Sleep(time.Duration(i) * time.Minute) + } } else { return "", spaceshipErr } diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/mock_DevPortalClient.go b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/mock_DevPortalClient.go index d865e10..9f80316 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/mock_DevPortalClient.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/mock_DevPortalClient.go @@ -7,7 +7,7 @@ import ( big "math/big" - devportalservice "github.com/bitrise-io/go-xcode/devportalservice" + devportalservice "github.com/bitrise-io/go-xcode/v2/devportalservice" mock "github.com/stretchr/testify/mock" ) diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/codesign/codesign.go b/vendor/github.com/bitrise-io/go-xcode/v2/codesign/codesign.go index 2fe3460..4f1321b 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/codesign/codesign.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/codesign/codesign.go @@ -5,13 +5,12 @@ import ( "time" "github.com/bitrise-io/go-utils/v2/log" - "github.com/bitrise-io/go-xcode/appleauth" "github.com/bitrise-io/go-xcode/certificateutil" - "github.com/bitrise-io/go-xcode/devportalservice" "github.com/bitrise-io/go-xcode/v2/autocodesign" "github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient" "github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect" "github.com/bitrise-io/go-xcode/v2/autocodesign/projectmanager" + "github.com/bitrise-io/go-xcode/v2/devportalservice" ) // AuthType ... @@ -51,7 +50,7 @@ type Opts struct { type Manager struct { opts Opts - appleAuthCredentials appleauth.Credentials + appleAuthCredentials devportalservice.Credentials bitriseTestDevices []devportalservice.TestDevice devPortalClientFactory devportalclient.Factory certDownloader autocodesign.CertificateProvider @@ -68,7 +67,7 @@ type Manager struct { // NewManagerWithArchive creates a codesign manager, which reads the code signing asset requirements from an XCArchive file. func NewManagerWithArchive( opts Opts, - appleAuth appleauth.Credentials, + appleAuth devportalservice.Credentials, bitriseTestDevices []devportalservice.TestDevice, clientFactory devportalclient.Factory, certDownloader autocodesign.CertificateProvider, @@ -95,7 +94,7 @@ func NewManagerWithArchive( // NewManagerWithProject creates a codesign manager, which reads the code signing asset requirements from an Xcode Project. func NewManagerWithProject( opts Opts, - appleAuth appleauth.Credentials, + appleAuth devportalservice.Credentials, bitriseTestDevices []devportalservice.TestDevice, clientFactory devportalclient.Factory, certDownloader autocodesign.CertificateProvider, @@ -194,15 +193,15 @@ func (m *Manager) PrepareCodesigning() (*devportalservice.APIKeyConnection, erro func SelectConnectionCredentials( authType AuthType, bitriseConnection *devportalservice.AppleDeveloperConnection, - inputs ConnectionOverrideInputs, logger log.Logger) (appleauth.Credentials, error) { + inputs ConnectionOverrideInputs, logger log.Logger) (devportalservice.Credentials, error) { if authType == APIKeyAuth && inputs.APIKeyPath != "" && inputs.APIKeyIssuerID != "" && inputs.APIKeyID != "" { logger.Infof("Overriding Bitrise Apple Service connection with Step-provided credentials (api_key_path, api_key_id, api_key_issuer_id)") - config, err := parseConnectionOverrideConfig(inputs.APIKeyPath, inputs.APIKeyID, inputs.APIKeyIssuerID, logger) + config, err := parseConnectionOverrideConfig(inputs.APIKeyPath, inputs.APIKeyID, inputs.APIKeyIssuerID, inputs.APIKeyEnterpriseAccount, logger) if err != nil { - return appleauth.Credentials{}, err + return devportalservice.Credentials{}, err } - return appleauth.Credentials{ + return devportalservice.Credentials{ APIKey: config, AppleID: nil, }, nil @@ -211,11 +210,11 @@ func SelectConnectionCredentials( if authType == APIKeyAuth { if bitriseConnection == nil || bitriseConnection.APIKeyConnection == nil { logger.Warnf(devportalclient.NotConnectedWarning) - return appleauth.Credentials{}, fmt.Errorf("Apple Service connection via App Store Connect API key is not estabilished") + return devportalservice.Credentials{}, fmt.Errorf("Apple Service connection via App Store Connect API key is not estabilished") } logger.Donef("Using Apple Service connection with API key.") - return appleauth.Credentials{ + return devportalservice.Credentials{ APIKey: bitriseConnection.APIKeyConnection, AppleID: nil, }, nil @@ -224,12 +223,12 @@ func SelectConnectionCredentials( if authType == AppleIDAuth { if bitriseConnection == nil || bitriseConnection.AppleIDConnection == nil { logger.Warnf(devportalclient.NotConnectedWarning) - return appleauth.Credentials{}, fmt.Errorf("Apple Service connection through Apple ID is not estabilished") + return devportalservice.Credentials{}, fmt.Errorf("Apple Service connection through Apple ID is not estabilished") } session, err := bitriseConnection.AppleIDConnection.FastlaneLoginSession() if err != nil { - return appleauth.Credentials{}, fmt.Errorf("failed to restore Apple ID login session: %w", err) + return devportalservice.Credentials{}, fmt.Errorf("failed to restore Apple ID login session: %w", err) } if session != "" && @@ -239,8 +238,8 @@ func SelectConnectionCredentials( } logger.Donef("Using Apple Service connection with Apple ID.") - return appleauth.Credentials{ - AppleID: &appleauth.AppleID{ + return devportalservice.Credentials{ + AppleID: &devportalservice.AppleID{ Username: bitriseConnection.AppleIDConnection.AppleID, Password: bitriseConnection.AppleIDConnection.Password, Session: session, @@ -253,7 +252,7 @@ func SelectConnectionCredentials( panic("Unexpected AuthType") } -func (m *Manager) selectCodeSigningStrategy(credentials appleauth.Credentials) (codeSigningStrategy, string, error) { +func (m *Manager) selectCodeSigningStrategy(credentials devportalservice.Credentials) (codeSigningStrategy, string, error) { const manualProfilesReason = "Using Bitrise-managed code signing assets with API key because Automatically managed signing is disabled in Xcode for the project." if credentials.AppleID != nil { @@ -272,6 +271,10 @@ func (m *Manager) selectCodeSigningStrategy(credentials appleauth.Credentials) ( return codeSigningBitriseAPIKey, "Using Bitrise-managed code signing assets with API key because 'xcodebuild -allowProvisioningUpdates' with API authentication requires Xcode 13 or higher.", nil } + if credentials.APIKey.EnterpriseAccount { + return codeSigningBitriseAPIKey, "Using Bitrise-managed code signing assets with API key because 'xcodebuild -allowProvisioningUpdates' for Enterprise Program is not yet supported.", nil + } + isManaged, err := m.detailsProvider.IsSigningManagedAutomatically() if err != nil { return codeSigningBitriseAPIKey, manualProfilesReason, err @@ -341,7 +344,7 @@ func (m *Manager) validateCertificatesForXcodeManagedSigning(certificates []cert return nil } -func (m *Manager) registerTestDevices(credentials appleauth.Credentials, devices []devportalservice.TestDevice) error { +func (m *Manager) registerTestDevices(credentials devportalservice.Credentials, devices []devportalservice.TestDevice) error { platform, err := m.detailsProvider.Platform() if err != nil { return fmt.Errorf("failed to read platform from project: %s", err) @@ -360,7 +363,7 @@ func (m *Manager) registerTestDevices(credentials appleauth.Credentials, devices return nil } -func (m *Manager) prepareCodeSigningWithBitrise(credentials appleauth.Credentials, testDevices []devportalservice.TestDevice) error { +func (m *Manager) prepareCodeSigningWithBitrise(credentials devportalservice.Credentials, testDevices []devportalservice.TestDevice) error { fmt.Println() m.logger.TDebugf("Analyzing project") appLayout, err := m.detailsProvider.GetAppLayout(m.opts.SignUITests) @@ -408,7 +411,7 @@ func (m *Manager) prepareCodeSigningWithBitrise(credentials appleauth.Credential return nil } -func (m *Manager) prepareAutomaticAssets(credentials appleauth.Credentials, appLayout autocodesign.AppLayout, typeToLocalCerts autocodesign.LocalCertificates, testDevicesToRegister []devportalservice.TestDevice) (map[autocodesign.DistributionType]autocodesign.AppCodesignAssets, error) { +func (m *Manager) prepareAutomaticAssets(credentials devportalservice.Credentials, appLayout autocodesign.AppLayout, typeToLocalCerts autocodesign.LocalCertificates, testDevicesToRegister []devportalservice.TestDevice) (map[autocodesign.DistributionType]autocodesign.AppCodesignAssets, error) { devPortalClient, err := m.devPortalClientFactory.Create(credentials, m.opts.TeamID) if err != nil { return nil, err diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/codesign/inputparse.go b/vendor/github.com/bitrise-io/go-xcode/v2/codesign/inputparse.go index eef0d44..842f637 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/codesign/inputparse.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/codesign/inputparse.go @@ -16,11 +16,11 @@ import ( "github.com/bitrise-io/go-utils/v2/command" "github.com/bitrise-io/go-utils/v2/log" "github.com/bitrise-io/go-utils/v2/retryhttp" - "github.com/bitrise-io/go-xcode/devportalservice" "github.com/bitrise-io/go-xcode/v2/autocodesign" "github.com/bitrise-io/go-xcode/v2/autocodesign/certdownloader" "github.com/bitrise-io/go-xcode/v2/autocodesign/codesignasset" "github.com/bitrise-io/go-xcode/v2/autocodesign/keychain" + "github.com/bitrise-io/go-xcode/v2/devportalservice" ) // Input ... @@ -37,9 +37,10 @@ type Input struct { // ConnectionOverrideInputs are used in steps to control the API key based auth credentials // This overrides the global API connection defined on Bitrise.io type ConnectionOverrideInputs struct { - APIKeyPath stepconf.Secret - APIKeyID string - APIKeyIssuerID string + APIKeyPath stepconf.Secret + APIKeyID string + APIKeyIssuerID string + APIKeyEnterpriseAccount bool } // Config ... @@ -83,7 +84,7 @@ func ParseConfig(input Input, cmdFactory command.Factory) (Config, error) { } // parseConnectionOverrideConfig validates and parses the step input-level connection parameters -func parseConnectionOverrideConfig(keyPathOrURL stepconf.Secret, keyID, keyIssuerID string, logger log.Logger) (*devportalservice.APIKeyConnection, error) { +func parseConnectionOverrideConfig(keyPathOrURL stepconf.Secret, keyID, keyIssuerID string, isEnterpriseAccount bool, logger log.Logger) (*devportalservice.APIKeyConnection, error) { var key []byte if strings.HasPrefix(string(keyPathOrURL), "https://") { resp, err := retryhttp.NewClient(logger).Get(string(keyPathOrURL)) @@ -120,9 +121,10 @@ func parseConnectionOverrideConfig(keyPathOrURL stepconf.Secret, keyID, keyIssue } return &devportalservice.APIKeyConnection{ - KeyID: strings.TrimSpace(keyID), - IssuerID: strings.TrimSpace(keyIssuerID), - PrivateKey: string(key), + KeyID: strings.TrimSpace(keyID), + IssuerID: strings.TrimSpace(keyIssuerID), + PrivateKey: string(key), + EnterpriseAccount: isEnterpriseAccount, }, nil } diff --git a/vendor/github.com/bitrise-io/go-xcode/devportalservice/devportalservice.go b/vendor/github.com/bitrise-io/go-xcode/v2/devportalservice/devportalservice.go similarity index 89% rename from vendor/github.com/bitrise-io/go-xcode/devportalservice/devportalservice.go rename to vendor/github.com/bitrise-io/go-xcode/v2/devportalservice/devportalservice.go index efcf6f7..1bfc82a 100644 --- a/vendor/github.com/bitrise-io/go-xcode/devportalservice/devportalservice.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/devportalservice/devportalservice.go @@ -12,10 +12,54 @@ import ( "text/template" "time" - "github.com/bitrise-io/go-utils/fileutil" - "github.com/bitrise-io/go-utils/log" + "github.com/bitrise-io/go-utils/v2/fileutil" + "github.com/bitrise-io/go-utils/v2/log" ) +const appleDeveloperConnectionPath = "apple_developer_portal_data.json" + +type cookie struct { + Name string `json:"name"` + Path string `json:"path"` + Value string `json:"value"` + Domain string `json:"domain"` + Secure bool `json:"secure"` + Expires string `json:"expires,omitempty"` + MaxAge int `json:"max_age,omitempty"` + Httponly bool `json:"httponly"` + ForDomain *bool `json:"for_domain,omitempty"` +} + +// AppleIDConnection represents a Bitrise.io Apple ID-based Apple Developer connection. +type AppleIDConnection struct { + AppleID string `json:"apple_id"` + Password string `json:"password"` + AppSpecificPassword string `json:"app_specific_password"` + SessionExpiryDate *time.Time `json:"connection_expiry_date"` + SessionCookies map[string][]cookie `json:"session_cookies"` +} + +// APIKeyConnection represents a Bitrise.io API key-based Apple Developer connection. +type APIKeyConnection struct { + KeyID string `json:"key_id"` + IssuerID string `json:"issuer_id"` + PrivateKey string `json:"private_key"` + EnterpriseAccount bool `json:"is_enterprise_account"` +} + +// IsEqualUDID compares two UDIDs (stored in the DeviceID field of TestDevice) +func IsEqualUDID(UDID string, otherUDID string) bool { + return normalizeDeviceUDID(UDID) == normalizeDeviceUDID(otherUDID) +} + +// AppleDeveloperConnection represents a Bitrise.io Apple Developer connection. +// https://devcenter.bitrise.io/getting-started/configuring-bitrise-steps-that-require-apple-developer-account-data/ +type AppleDeveloperConnection struct { + AppleIDConnection *AppleIDConnection + APIKeyConnection *APIKeyConnection + TestDevices, DuplicatedTestDevices []TestDevice +} + type httpClient interface { Do(req *http.Request) (*http.Response, error) } @@ -27,24 +71,24 @@ type AppleDeveloperConnectionProvider interface { // BitriseClient implements AppleDeveloperConnectionProvider through the Bitrise.io API. type BitriseClient struct { - httpClient httpClient - buildURL, buildAPIToken string + log log.Logger + filemanager fileutil.FileManager + httpClient httpClient - readBytesFromFile func(pth string) ([]byte, error) + buildURL, buildAPIToken string } // NewBitriseClient creates a new instance of BitriseClient. -func NewBitriseClient(client httpClient, buildURL, buildAPIToken string) *BitriseClient { +func NewBitriseClient(logger log.Logger, filemanager fileutil.FileManager, client httpClient, buildURL, buildAPIToken string) *BitriseClient { return &BitriseClient{ - httpClient: client, - buildURL: buildURL, - buildAPIToken: buildAPIToken, - readBytesFromFile: fileutil.ReadBytesFromFile, + log: logger, + filemanager: filemanager, + httpClient: client, + buildURL: buildURL, + buildAPIToken: buildAPIToken, } } -const appleDeveloperConnectionPath = "apple_developer_portal_data.json" - func privateKeyWithHeader(privateKey string) string { if strings.HasPrefix(privateKey, "-----BEGIN PRIVATE KEY----") { return privateKey @@ -57,6 +101,15 @@ func privateKeyWithHeader(privateKey string) string { ) } +func (c *BitriseClient) readBytesFromFile(filepath string) ([]byte, error) { + reader, err := c.filemanager.OpenReaderIfExists(filepath) + if err != nil { + return []byte{}, err + } + + return io.ReadAll(reader) +} + // GetAppleDeveloperConnection fetches the Bitrise.io Apple Developer connection. func (c *BitriseClient) GetAppleDeveloperConnection() (*AppleDeveloperConnection, error) { var rawCreds []byte @@ -122,7 +175,7 @@ func (c *BitriseClient) download() ([]byte, error) { // The client must close the response body when finished with it defer func() { if cerr := resp.Body.Close(); cerr != nil { - log.Warnf("Failed to close response body: %s", cerr) + c.log.Warnf("Failed to close response body: %s", cerr) } }() @@ -138,47 +191,6 @@ func (c *BitriseClient) download() ([]byte, error) { return body, nil } -type cookie struct { - Name string `json:"name"` - Path string `json:"path"` - Value string `json:"value"` - Domain string `json:"domain"` - Secure bool `json:"secure"` - Expires string `json:"expires,omitempty"` - MaxAge int `json:"max_age,omitempty"` - Httponly bool `json:"httponly"` - ForDomain *bool `json:"for_domain,omitempty"` -} - -// AppleIDConnection represents a Bitrise.io Apple ID-based Apple Developer connection. -type AppleIDConnection struct { - AppleID string `json:"apple_id"` - Password string `json:"password"` - AppSpecificPassword string `json:"app_specific_password"` - SessionExpiryDate *time.Time `json:"connection_expiry_date"` - SessionCookies map[string][]cookie `json:"session_cookies"` -} - -// APIKeyConnection represents a Bitrise.io API key-based Apple Developer connection. -type APIKeyConnection struct { - KeyID string `json:"key_id"` - IssuerID string `json:"issuer_id"` - PrivateKey string `json:"private_key"` -} - -// IsEqualUDID compares two UDIDs (stored in the DeviceID field of TestDevice) -func IsEqualUDID(UDID string, otherUDID string) bool { - return normalizeDeviceUDID(UDID) == normalizeDeviceUDID(otherUDID) -} - -// AppleDeveloperConnection represents a Bitrise.io Apple Developer connection. -// https://devcenter.bitrise.io/getting-started/configuring-bitrise-steps-that-require-apple-developer-account-data/ -type AppleDeveloperConnection struct { - AppleIDConnection *AppleIDConnection - APIKeyConnection *APIKeyConnection - TestDevices, DuplicatedTestDevices []TestDevice -} - // FastlaneLoginSession returns the Apple ID login session in a ruby/object:HTTP::Cookie format. // The session can be used as a value for FASTLANE_SESSION environment variable: https://docs.fastlane.tools/best-practices/continuous-integration/#two-step-or-two-factor-auth. func (c *AppleIDConnection) FastlaneLoginSession() (string, error) { diff --git a/vendor/github.com/bitrise-io/go-xcode/devportalservice/devportalservice_testdata.go b/vendor/github.com/bitrise-io/go-xcode/v2/devportalservice/devportalservice_testdata.go similarity index 100% rename from vendor/github.com/bitrise-io/go-xcode/devportalservice/devportalservice_testdata.go rename to vendor/github.com/bitrise-io/go-xcode/v2/devportalservice/devportalservice_testdata.go diff --git a/vendor/github.com/bitrise-io/go-xcode/devportalservice/errors.go b/vendor/github.com/bitrise-io/go-xcode/v2/devportalservice/errors.go similarity index 100% rename from vendor/github.com/bitrise-io/go-xcode/devportalservice/errors.go rename to vendor/github.com/bitrise-io/go-xcode/v2/devportalservice/errors.go diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/devportalservice/mock_filemanager.go b/vendor/github.com/bitrise-io/go-xcode/v2/devportalservice/mock_filemanager.go new file mode 100644 index 0000000..627481e --- /dev/null +++ b/vendor/github.com/bitrise-io/go-xcode/v2/devportalservice/mock_filemanager.go @@ -0,0 +1,59 @@ +package devportalservice + +import ( + "io" + "os" + "strings" + + "github.com/bitrise-io/go-utils/v2/fileutil" +) + +type mockFileReader struct { + contents string +} + +func newMockFileReader(contents string) fileutil.FileManager { + return &mockFileReader{ + contents: contents, + } +} + +// Open ... +func (r *mockFileReader) Open(path string) (*os.File, error) { + panic("not implemented") +} + +// OpenReaderIfExists ... +func (r *mockFileReader) OpenReaderIfExists(path string) (io.Reader, error) { + return io.NopCloser(strings.NewReader(r.contents)), nil +} + +// ReadDirEntryNames ... +func (r *mockFileReader) ReadDirEntryNames(path string) ([]string, error) { + panic("not implemented") +} + +// Remove ... +func (r *mockFileReader) Remove(path string) error { + panic("not implemented") +} + +// RemoveAll ... +func (r *mockFileReader) RemoveAll(path string) error { + panic("not implemented") +} + +// Write ... +func (r *mockFileReader) Write(path string, value string, perm os.FileMode) error { + panic("not implemented") +} + +// WriteBytes ... +func (r *mockFileReader) WriteBytes(path string, value []byte) error { + panic("not implemented") +} + +// FileSizeInBytes ... +func (r *mockFileReader) FileSizeInBytes(pth string) (int64, error) { + panic("not implemented") +} diff --git a/vendor/github.com/bitrise-io/go-xcode/devportalservice/testdevice.go b/vendor/github.com/bitrise-io/go-xcode/v2/devportalservice/testdevice.go similarity index 100% rename from vendor/github.com/bitrise-io/go-xcode/devportalservice/testdevice.go rename to vendor/github.com/bitrise-io/go-xcode/v2/devportalservice/testdevice.go diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/devportalservice/validated_credentials.go b/vendor/github.com/bitrise-io/go-xcode/v2/devportalservice/validated_credentials.go new file mode 100644 index 0000000..c030153 --- /dev/null +++ b/vendor/github.com/bitrise-io/go-xcode/v2/devportalservice/validated_credentials.go @@ -0,0 +1,26 @@ +package devportalservice + +// Credentials contains only one of Apple ID (the session cookies already checked) or APIKey auth info +type Credentials struct { + AppleID *AppleID + APIKey *APIKeyConnection +} + +// AppleID contains Apple ID auth info +// +// Without 2FA: +// +// Required: username, password +// +// With 2FA: +// +// Required: username, password, appSpecificPassword +// session (Only for Fastlane, set as FASTLANE_SESSION) +// +// As Fastlane spaceship uses: +// - iTMSTransporter: it requires Username + Password (or App-specific password with 2FA) +// - TunesAPI: it requires Username + Password (+ 2FA session with 2FA) +type AppleID struct { + Username, Password string + Session, AppSpecificPassword string +} diff --git a/vendor/modules.txt b/vendor/modules.txt index cbba3c0..be85144 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -33,15 +33,14 @@ github.com/bitrise-io/go-utils/ziputil ## explicit; go 1.17 github.com/bitrise-io/go-utils/v2/command github.com/bitrise-io/go-utils/v2/env +github.com/bitrise-io/go-utils/v2/fileutil github.com/bitrise-io/go-utils/v2/log github.com/bitrise-io/go-utils/v2/log/colorstring github.com/bitrise-io/go-utils/v2/pathutil github.com/bitrise-io/go-utils/v2/retryhttp # github.com/bitrise-io/go-xcode v1.1.1 ## explicit; go 1.20 -github.com/bitrise-io/go-xcode/appleauth github.com/bitrise-io/go-xcode/certificateutil -github.com/bitrise-io/go-xcode/devportalservice github.com/bitrise-io/go-xcode/export github.com/bitrise-io/go-xcode/exportoptions github.com/bitrise-io/go-xcode/models @@ -55,7 +54,7 @@ github.com/bitrise-io/go-xcode/xcodeproject/serialized github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj github.com/bitrise-io/go-xcode/xcodeproject/xcscheme github.com/bitrise-io/go-xcode/xcodeproject/xcworkspace -# github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.48 +# github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.50 ## explicit; go 1.20 github.com/bitrise-io/go-xcode/v2/autocodesign github.com/bitrise-io/go-xcode/v2/autocodesign/certdownloader @@ -70,6 +69,7 @@ github.com/bitrise-io/go-xcode/v2/autocodesign/localcodesignasset github.com/bitrise-io/go-xcode/v2/autocodesign/profiledownloader github.com/bitrise-io/go-xcode/v2/autocodesign/projectmanager github.com/bitrise-io/go-xcode/v2/codesign +github.com/bitrise-io/go-xcode/v2/devportalservice github.com/bitrise-io/go-xcode/v2/xcarchive # github.com/davecgh/go-spew v1.1.1 ## explicit