autocodesign

package
v2.0.0-alpha.44 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 18, 2024 License: MIT Imports: 14 Imported by: 3

Documentation

Overview

Package autocodesign is a framework for automatic code signing.

Contains common types, interfaces and logic needed for codesigning. Parsing an Xcode project or archive and applying settings is not part of the package, for modularity.

Example
package main

import (
	"errors"
	"fmt"

	"github.com/bitrise-io/go-steputils/v2/stepconf"
	"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/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/certdownloader"
	"github.com/bitrise-io/go-xcode/v2/autocodesign/codesignasset"
	"github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient"
	"github.com/bitrise-io/go-xcode/v2/autocodesign/keychain"
	"github.com/bitrise-io/go-xcode/v2/autocodesign/localcodesignasset"
	"github.com/bitrise-io/go-xcode/v2/autocodesign/projectmanager"
	"github.com/bitrise-io/go-xcode/v2/codesign"
)

type config struct {
	BuildURL            string
	BuildAPIToken       string
	TeamID              string
	KeychainPath        string
	KeychainPassword    stepconf.Secret
	ProjectPath         string
	Scheme              string
	Configuration       string
	DistributionType    autocodesign.DistributionType
	RegisterTestDevices bool
	MinProfileDaysValid int
	VerboseLog          bool
}

func main() {
	cfg := config{
		DistributionType: autocodesign.Development,
	}
	var authClientType codesign.AuthType
	certsWithPrivateKey := []certdownloader.CertificateAndPassphrase{}

	logger := log.NewLogger()
	f := devportalclient.NewFactory(logger)
	connection, err := f.CreateBitriseConnection(cfg.BuildURL, cfg.BuildAPIToken)
	if err != nil {
		panic(err)
	}

	var authSource appleauth.Source
	switch authClientType {
	case codesign.APIKeyAuth:
		authSource = &appleauth.ConnectionAPIKeySource{}
	case codesign.AppleIDAuth:
		authSource = &appleauth.ConnectionAppleIDFastlaneSource{}
	default:
		panic("missing implementation")
	}

	authConfig, err := appleauth.Select(connection, []appleauth.Source{authSource}, appleauth.Inputs{})
	if err != nil {
		if errors.Is(err, &appleauth.MissingAuthConfigError{}) {
			panic("Apple Service connection is unset")
		}

		panic(fmt.Sprintf("could not select Apple authentication credentials: %s", err))
	}

	devPortalClient, err := f.Create(authConfig, cfg.TeamID)
	if err != nil {
		panic(err)
	}

	keychain, err := keychain.New(cfg.KeychainPath, cfg.KeychainPassword, command.NewFactory(env.NewRepository()))
	if err != nil {
		panic(fmt.Sprintf("failed to initialize keychain: %s", err))
	}

	certDownloader := certdownloader.NewDownloader(certsWithPrivateKey, retry.NewHTTPClient().StandardClient())
	certs, err := certDownloader.GetCertificates()
	if err != nil {
		panic(fmt.Errorf("failed to download certificates: %w", err))
	}

	typeToLocalCerts, err := autocodesign.GetValidLocalCertificates(certs)
	if err != nil {
		panic(err)
	}

	profileProvider := localcodesignasset.NewProvisioningProfileProvider()
	profileConverter := localcodesignasset.NewProvisioningProfileConverter()
	localCodesignAssetManager := localcodesignasset.NewManager(profileProvider, profileConverter)
	manager := autocodesign.NewCodesignAssetManager(devPortalClient, codesignasset.NewWriter(*keychain), localCodesignAssetManager)

	// Analyzing project
	fmt.Println()
	logger.Infof("Analyzing project")
	project, err := projectmanager.NewProject(projectmanager.InitParams{
		ProjectOrWorkspacePath: cfg.ProjectPath,
		SchemeName:             cfg.Scheme,
		ConfigurationName:      cfg.Configuration,
	})
	if err != nil {
		panic(err)
	}

	appLayout, err := project.GetAppLayout(true)
	if err != nil {
		panic(err)
	}

	distribution := cfg.DistributionType
	var testDevices []devportalservice.TestDevice
	if cfg.RegisterTestDevices {
		testDevices = connection.TestDevices
	}
	codesignAssetsByDistributionType, err := manager.EnsureCodesignAssets(appLayout, autocodesign.CodesignAssetsOpts{
		DistributionType:        distribution,
		TypeToLocalCertificates: typeToLocalCerts,
		BitriseTestDevices:      testDevices,
		MinProfileValidityDays:  cfg.MinProfileDaysValid,
		VerboseLog:              cfg.VerboseLog,
	})
	if err != nil {
		panic(fmt.Sprintf("Automatic code signing failed: %s", err))
	}

	if err := project.ForceCodesignAssets(distribution, codesignAssetsByDistributionType); err != nil {
		panic(fmt.Sprintf("Failed to force codesign settings: %s", err))
	}
}
Output:

Index

Examples

Constants

View Source
const ICloudIdentifiersEntitlementKey = "com.apple.developer.icloud-container-identifiers"

ICloudIdentifiersEntitlementKey ...

Variables

CertificateTypeByDistribution ...

View Source
var DataProtections = map[string]appstoreconnect.CapabilityOptionKey{
	"NSFileProtectionComplete":                             appstoreconnect.CompleteProtection,
	"NSFileProtectionCompleteUnlessOpen":                   appstoreconnect.ProtectedUnlessOpen,
	"NSFileProtectionCompleteUntilFirstUserAuthentication": appstoreconnect.ProtectedUntilFirstUserAuth,
}

DataProtections ...

PlatformToProfileTypeByDistribution ...

ProfileTypeToDistribution ...

ProfileTypeToPlatform ...

Functions

func CreateWildcardBundleID

func CreateWildcardBundleID(bundleID string) (string, error)

CreateWildcardBundleID creates a wildcard bundle identifier, by replacing the provided bundle id's last component with an asterisk (*).

func DistributionTypeRequiresDeviceList

func DistributionTypeRequiresDeviceList(distrTypes []DistributionType) bool

DistributionTypeRequiresDeviceList returns true if the provided distribution method requires a provisioning profile with a device list.

func EnsureTestDevices

func EnsureTestDevices(deviceClient DevPortalClient, testDevices []devportalservice.TestDevice, platform Platform) ([]appstoreconnect.Device, error)

EnsureTestDevices fetches devices from Apple, and register missing devices. Leave testDevices empty, to skip device registration.

func FindMissingContainers

func FindMissingContainers(projectEnts, profileEnts Entitlements) ([]string, error)

FindMissingContainers ...

Types

type AppCodesignAssets

type AppCodesignAssets struct {
	ArchivableTargetProfilesByBundleID map[string]Profile
	UITestTargetProfilesByBundleID     map[string]Profile
	Certificate                        certificateutil.CertificateInfoModel
}

AppCodesignAssets is the result of ensuring codesigning assets

type AppLayout

type AppLayout struct {
	Platform                               Platform
	EntitlementsByArchivableTargetBundleID map[string]Entitlements
	UITestTargetBundleIDs                  []string
}

AppLayout contains codesigning related settings that are needed to ensure codesigning files

type AssetWriter

type AssetWriter interface {
	Write(codesignAssetsByDistributionType map[DistributionType]AppCodesignAssets) error
	InstallCertificate(certificate certificateutil.CertificateInfoModel) error
	InstallProfile(profile Profile) error
}

AssetWriter ...

type Certificate

type Certificate struct {
	CertificateInfo certificateutil.CertificateInfoModel
	ID              string
}

Certificate is certificate present on Apple App Store Connect API, could match a local certificate

func SelectCertificate

func SelectCertificate(certsByType map[appstoreconnect.CertificateType][]Certificate, distrType DistributionType) (*Certificate, error)

SelectCertificate selects the first certificate with the given distribution type.

type CertificateProvider

type CertificateProvider interface {
	GetCertificates() ([]certificateutil.CertificateInfoModel, error)
}

CertificateProvider returns codesigning certificates (with private key)

type CodesignAssetManager

type CodesignAssetManager interface {
	EnsureCodesignAssets(appLayout AppLayout, opts CodesignAssetsOpts) (map[DistributionType]AppCodesignAssets, error)
}

CodesignAssetManager ...

func NewCodesignAssetManager

func NewCodesignAssetManager(devPortalClient DevPortalClient, assetWriter AssetWriter, localCodeSignAssetManager LocalCodeSignAssetManager) CodesignAssetManager

NewCodesignAssetManager ...

type CodesignAssetsOpts

type CodesignAssetsOpts struct {
	DistributionType                  DistributionType
	TypeToLocalCertificates           LocalCertificates
	BitriseTestDevices                []devportalservice.TestDevice
	MinProfileValidityDays            int
	FallbackToLocalAssetsOnAPIFailure bool
	VerboseLog                        bool
}

CodesignAssetsOpts are codesigning related parameters that are not specified by the project (or archive)

type DetailedError

type DetailedError struct {
	ErrorMessage   string
	Title          string
	Description    string
	Recommendation string
}

DetailedError ...

func (DetailedError) Error

func (e DetailedError) Error() string

type DevPortalClient

type DevPortalClient interface {
	Login() error

	QueryCertificateBySerial(serial big.Int) (Certificate, error)
	QueryAllIOSCertificates() (map[appstoreconnect.CertificateType][]Certificate, error)

	ListDevices(UDID string, platform appstoreconnect.DevicePlatform) ([]appstoreconnect.Device, error)
	RegisterDevice(testDevice devportalservice.TestDevice) (*appstoreconnect.Device, error)

	FindProfile(name string, profileType appstoreconnect.ProfileType) (Profile, error)
	DeleteProfile(id string) error
	CreateProfile(name string, profileType appstoreconnect.ProfileType, bundleID appstoreconnect.BundleID, certificateIDs []string, deviceIDs []string) (Profile, error)

	FindBundleID(bundleIDIdentifier string) (*appstoreconnect.BundleID, error)
	CheckBundleIDEntitlements(bundleID appstoreconnect.BundleID, appEntitlements Entitlements) error
	SyncBundleID(bundleID appstoreconnect.BundleID, appEntitlements Entitlements) error
	CreateBundleID(bundleIDIdentifier, appIDName string) (*appstoreconnect.BundleID, error)
}

DevPortalClient abstract away the Apple Developer Portal API

type DistributionType

type DistributionType string

DistributionType ...

var (
	Development DistributionType = "development"
	AppStore    DistributionType = "app-store"
	AdHoc       DistributionType = "ad-hoc"
	Enterprise  DistributionType = "enterprise"
)

DistributionTypes ...

type Entitlement

type Entitlement serialized.Object

Entitlement ...

func (Entitlement) AppearsOnDeveloperPortal

func (e Entitlement) AppearsOnDeveloperPortal() bool

AppearsOnDeveloperPortal reports whether the given (project) Entitlement needs to be registered on Apple Developer Portal or not. List of services, to be registered: https://developer.apple.com/documentation/appstoreconnectapi/capabilitytype.

func (Entitlement) Capability

Capability ...

func (Entitlement) Equal

func (e Entitlement) Equal(cap appstoreconnect.BundleIDCapability, allEntitlements Entitlements) (bool, error)

Equal ...

func (Entitlement) IsProfileAttached

func (e Entitlement) IsProfileAttached() bool

IsProfileAttached returns an error if an entitlement does not match a Capability but needs to be addded to the profile as an additional entitlement, after submitting a request to Apple.

type Entitlements

type Entitlements serialized.Object

Entitlements is all the entitlements that are contained in a target or profile

func ParseRawProfileEntitlements

func ParseRawProfileEntitlements(profileContents []byte) (Entitlements, error)

ParseRawProfileEntitlements ...

func (Entitlements) ICloudContainers

func (e Entitlements) ICloudContainers() ([]string, error)

ICloudContainers returns the list of iCloud containers

type ErrAppClipAppID

type ErrAppClipAppID struct {
}

ErrAppClipAppID ...

func (ErrAppClipAppID) Error

func (ErrAppClipAppID) Error() string

Error ...

type ErrAppClipAppIDWithAppleSigning

type ErrAppClipAppIDWithAppleSigning struct {
}

ErrAppClipAppIDWithAppleSigning ...

func (ErrAppClipAppIDWithAppleSigning) Error

Error ...

type LocalCertificates

LocalCertificates is a map from the certificate type (development, distribution) to an array of installed certs

func GetValidLocalCertificates

func GetValidLocalCertificates(certificates []certificateutil.CertificateInfoModel) (LocalCertificates, error)

GetValidLocalCertificates returns validated and deduplicated local certificates

type LocalCodeSignAssetManager

type LocalCodeSignAssetManager interface {
	FindCodesignAssets(appLayout AppLayout, distrType DistributionType, certsByType map[appstoreconnect.CertificateType][]Certificate, deviceIDs []string, minProfileDaysValid int) (*AppCodesignAssets, *AppLayout, error)
}

LocalCodeSignAssetManager ...

type LocalProfile

type LocalProfile struct {
	Profile Profile
	Info    profileutil.ProvisioningProfileInfoModel
}

LocalProfile ...

type MockAssetWriter

type MockAssetWriter struct {
	mock.Mock
}

MockAssetWriter is an autogenerated mock type for the AssetWriter type

func (*MockAssetWriter) InstallCertificate

func (_m *MockAssetWriter) InstallCertificate(certificate certificateutil.CertificateInfoModel) error

InstallCertificate provides a mock function with given fields: certificate

func (*MockAssetWriter) InstallProfile

func (_m *MockAssetWriter) InstallProfile(profile Profile) error

InstallProfile provides a mock function with given fields: profile

func (*MockAssetWriter) Write

func (_m *MockAssetWriter) Write(codesignAssetsByDistributionType map[DistributionType]AppCodesignAssets) error

Write provides a mock function with given fields: codesignAssetsByDistributionType

type MockCertificateProvider

type MockCertificateProvider struct {
	mock.Mock
}

MockCertificateProvider is an autogenerated mock type for the CertificateProvider type

func (*MockCertificateProvider) GetCertificates

GetCertificates provides a mock function with given fields:

type MockDevPortalClient

type MockDevPortalClient struct {
	mock.Mock
}

MockDevPortalClient is an autogenerated mock type for the DevPortalClient type

func NewMockDevPortalClient

func NewMockDevPortalClient(t mockConstructorTestingTNewMockDevPortalClient) *MockDevPortalClient

NewMockDevPortalClient creates a new instance of MockDevPortalClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.

func (*MockDevPortalClient) CheckBundleIDEntitlements

func (_m *MockDevPortalClient) CheckBundleIDEntitlements(bundleID appstoreconnect.BundleID, appEntitlements Entitlements) error

CheckBundleIDEntitlements provides a mock function with given fields: bundleID, appEntitlements

func (*MockDevPortalClient) CreateBundleID

func (_m *MockDevPortalClient) CreateBundleID(bundleIDIdentifier string, appIDName string) (*appstoreconnect.BundleID, error)

CreateBundleID provides a mock function with given fields: bundleIDIdentifier, appIDName

func (*MockDevPortalClient) CreateProfile

func (_m *MockDevPortalClient) CreateProfile(name string, profileType appstoreconnect.ProfileType, bundleID appstoreconnect.BundleID, certificateIDs []string, deviceIDs []string) (Profile, error)

CreateProfile provides a mock function with given fields: name, profileType, bundleID, certificateIDs, deviceIDs

func (*MockDevPortalClient) DeleteProfile

func (_m *MockDevPortalClient) DeleteProfile(id string) error

DeleteProfile provides a mock function with given fields: id

func (*MockDevPortalClient) FindBundleID

func (_m *MockDevPortalClient) FindBundleID(bundleIDIdentifier string) (*appstoreconnect.BundleID, error)

FindBundleID provides a mock function with given fields: bundleIDIdentifier

func (*MockDevPortalClient) FindProfile

func (_m *MockDevPortalClient) FindProfile(name string, profileType appstoreconnect.ProfileType) (Profile, error)

FindProfile provides a mock function with given fields: name, profileType

func (*MockDevPortalClient) ListDevices

ListDevices provides a mock function with given fields: UDID, platform

func (*MockDevPortalClient) Login

func (_m *MockDevPortalClient) Login() error

Login provides a mock function with given fields:

func (*MockDevPortalClient) QueryAllIOSCertificates

func (_m *MockDevPortalClient) QueryAllIOSCertificates() (map[appstoreconnect.CertificateType][]Certificate, error)

QueryAllIOSCertificates provides a mock function with given fields:

func (*MockDevPortalClient) QueryCertificateBySerial

func (_m *MockDevPortalClient) QueryCertificateBySerial(serial big.Int) (Certificate, error)

QueryCertificateBySerial provides a mock function with given fields: serial

func (*MockDevPortalClient) RegisterDevice

func (_m *MockDevPortalClient) RegisterDevice(testDevice devportalservice.TestDevice) (*appstoreconnect.Device, error)

RegisterDevice provides a mock function with given fields: testDevice

func (*MockDevPortalClient) SyncBundleID

func (_m *MockDevPortalClient) SyncBundleID(bundleID appstoreconnect.BundleID, appEntitlements Entitlements) error

SyncBundleID provides a mock function with given fields: bundleID, appEntitlements

type MockLocalCodeSignAssetManager

type MockLocalCodeSignAssetManager struct {
	mock.Mock
}

MockLocalCodeSignAssetManager is an autogenerated mock type for the LocalCodeSignAssetManager type

func (*MockLocalCodeSignAssetManager) FindCodesignAssets

func (_m *MockLocalCodeSignAssetManager) FindCodesignAssets(appLayout AppLayout, distrType DistributionType, certsByType map[appstoreconnect.CertificateType][]Certificate, deviceIDs []string, minProfileDaysValid int) (*AppCodesignAssets, *AppLayout, error)

FindCodesignAssets provides a mock function with given fields: appLayout, distrType, certsByType, deviceIDs, minProfileDaysValid

type MockProfile

type MockProfile struct {
	mock.Mock
}

MockProfile is an autogenerated mock type for the Profile type

func (*MockProfile) Attributes

Attributes provides a mock function with given fields:

func (*MockProfile) BundleID

func (_m *MockProfile) BundleID() (appstoreconnect.BundleID, error)

BundleID provides a mock function with given fields:

func (*MockProfile) CertificateIDs

func (_m *MockProfile) CertificateIDs() ([]string, error)

CertificateIDs provides a mock function with given fields:

func (*MockProfile) DeviceIDs

func (_m *MockProfile) DeviceIDs() ([]string, error)

DeviceIDs provides a mock function with given fields:

func (*MockProfile) Entitlements

func (_m *MockProfile) Entitlements() (Entitlements, error)

Entitlements provides a mock function with given fields:

func (*MockProfile) ID

func (_m *MockProfile) ID() string

ID provides a mock function with given fields:

type NonmatchingProfileError

type NonmatchingProfileError struct {
	Reason string
}

NonmatchingProfileError is returned when a profile/bundle ID does not match project requirements It is not a fatal error, as the profile can be regenerated

func (NonmatchingProfileError) Error

func (e NonmatchingProfileError) Error() string

type Platform

type Platform string

Platform ...

const (
	IOS   Platform = "iOS"
	TVOS  Platform = "tvOS"
	MacOS Platform = "macOS"
)

Const

type Profile

type Profile interface {
	ID() string
	Attributes() appstoreconnect.ProfileAttributes
	CertificateIDs() ([]string, error)
	DeviceIDs() ([]string, error)
	BundleID() (appstoreconnect.BundleID, error)
	Entitlements() (Entitlements, error)
}

Profile represents a provisioning profiles

type ProfileProvider

type ProfileProvider interface {
	IsAvailable() bool
	GetProfiles() ([]LocalProfile, error)
}

ProfileProvider returns provisioning profiles

type ProfilesInconsistentError

type ProfilesInconsistentError struct {
	// contains filtered or unexported fields
}

ProfilesInconsistentError is returned when a profile is deleted by an other actor

func NewProfilesInconsistentError

func NewProfilesInconsistentError(wrapErr error) ProfilesInconsistentError

NewProfilesInconsistentError ...

func (ProfilesInconsistentError) Error

func (ProfilesInconsistentError) Unwrap

func (e ProfilesInconsistentError) Unwrap() error

Directories

Path Synopsis
Package certdownloader implements a autocodesign.CertificateProvider which fetches Bitrise hosted Xcode codesigning certificates.
Package certdownloader implements a autocodesign.CertificateProvider which fetches Bitrise hosted Xcode codesigning certificates.
Package codesignasset implements a autocodesign.AssetWriter which writes certificates, profiles to the keychain and filesystem.
Package codesignasset implements a autocodesign.AssetWriter which writes certificates, profiles to the keychain and filesystem.
Package devportalclient contains glue code to select and initialize a autocodesign.DevPortalClient either using Apple ID or API key authentication.
Package devportalclient contains glue code to select and initialize a autocodesign.DevPortalClient either using Apple ID or API key authentication.
appstoreconnect
Package appstoreconnect implements a client for the App Store Connect API.
Package appstoreconnect implements a client for the App Store Connect API.
appstoreconnectclient
Package appstoreconnectclient implements autocodesign.DevPortalClient, using an API key as the authentication method.
Package appstoreconnectclient implements autocodesign.DevPortalClient, using an API key as the authentication method.
spaceship
Package spaceship implements autocodesign.DevPortalClient, using Apple ID as the authentication method.
Package spaceship implements autocodesign.DevPortalClient, using Apple ID as the authentication method.
Package keychain contains methods to manage and install certificates to the MacOS keychain.
Package keychain contains methods to manage and install certificates to the MacOS keychain.
Package projectmanager parses and edits an Xcode project.
Package projectmanager parses and edits an Xcode project.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL