mirror of
https://github.com/fleetdm/fleet
synced 2026-05-11 03:00:58 +00:00
125 lines
3.1 KiB
Go
125 lines
3.1 KiB
Go
package packaging
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"sync"
|
|
|
|
"github.com/fatih/color"
|
|
"github.com/mitchellh/gon/notarize"
|
|
"github.com/mitchellh/gon/staple"
|
|
"github.com/rs/zerolog/log"
|
|
)
|
|
|
|
// Notarize will do the Notarization step. Note that the provided path must be a .zip, .dmg or .pkg.
|
|
func Notarize(path, bundleIdentifier string) error {
|
|
username, ok := os.LookupEnv("AC_USERNAME")
|
|
if !ok {
|
|
return errors.New("AC_USERNAME must be set in environment")
|
|
}
|
|
|
|
password, ok := os.LookupEnv("AC_PASSWORD")
|
|
if !ok {
|
|
return errors.New("AC_PASSWORD must be set in environment")
|
|
}
|
|
|
|
// This is typically optional, though seems to be required if the organization has an Apple
|
|
// Enterprise Dev account.
|
|
teamID, _ := os.LookupEnv("AC_TEAM_ID")
|
|
|
|
// FIXME Ignoring new log output for now.
|
|
_, notary_log, err := notarize.Notarize(
|
|
context.Background(),
|
|
¬arize.Options{
|
|
File: path,
|
|
DeveloperId: username,
|
|
Password: password,
|
|
Provider: teamID,
|
|
Status: &statusHuman{
|
|
Lock: &sync.Mutex{},
|
|
},
|
|
},
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("notarize: %w", err)
|
|
}
|
|
|
|
log.Info().Str("logs", notary_log.JobId).Msg("notarization completed")
|
|
|
|
return nil
|
|
}
|
|
|
|
// Staple will do the "stapling" step of Notarization. Note that this only works on .app, .pkg and .dmg
|
|
// (not .zip or plain binaries).
|
|
func Staple(path string) error {
|
|
if err := staple.Staple(context.Background(), &staple.Options{File: path}); err != nil {
|
|
return fmt.Errorf("staple notarization: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// NotarizeStaple will notarize and staple a macOS artifact.
|
|
func NotarizeStaple(path, bundleIdentifier string) error {
|
|
if err := Notarize(path, bundleIdentifier); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := Staple(path); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// This status plugin copied from
|
|
// https://github.com/mitchellh/gon/blob/v0.2.3/cmd/gon/status_human.go since it
|
|
// is not exposed from the gon library.
|
|
|
|
// statusHuman implements notarize.Status and outputs information to
|
|
// the CLI for human consumption.
|
|
type statusHuman struct {
|
|
Prefix string
|
|
Lock *sync.Mutex
|
|
|
|
lastInfoStatus string
|
|
lastLogStatus string
|
|
}
|
|
|
|
func (s *statusHuman) Submitting() {
|
|
s.Lock.Lock()
|
|
defer s.Lock.Unlock()
|
|
|
|
color.New().Fprintf(os.Stdout, " %sSubmitting file for notarization...\n", s.Prefix)
|
|
}
|
|
|
|
func (s *statusHuman) Submitted(uuid string) {
|
|
s.Lock.Lock()
|
|
defer s.Lock.Unlock()
|
|
|
|
color.New().Fprintf(os.Stdout, " %sSubmitted. Request UUID: %s\n", s.Prefix, uuid)
|
|
color.New().Fprintf(
|
|
os.Stdout, " %sWaiting for results from Apple. This can take minutes to hours.\n", s.Prefix)
|
|
}
|
|
|
|
func (s *statusHuman) InfoStatus(info notarize.Info) {
|
|
s.Lock.Lock()
|
|
defer s.Lock.Unlock()
|
|
|
|
if info.Status != s.lastInfoStatus {
|
|
s.lastInfoStatus = info.Status
|
|
color.New().Fprintf(os.Stdout, " %sInfoStatus: %s\n", s.Prefix, info.Status)
|
|
}
|
|
}
|
|
|
|
func (s *statusHuman) LogStatus(log notarize.Log) {
|
|
s.Lock.Lock()
|
|
defer s.Lock.Unlock()
|
|
|
|
if log.Status != s.lastLogStatus {
|
|
s.lastLogStatus = log.Status
|
|
color.New().Fprintf(os.Stdout, " %sLogStatus: %s\n", s.Prefix, log.Status)
|
|
}
|
|
}
|