2024-04-19 22:27:50 -03:00
|
|
|
package notary
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/anchore/quill/quill"
|
|
|
|
"github.com/anchore/quill/quill/notary"
|
|
|
|
"github.com/anchore/quill/quill/pki/load"
|
|
|
|
"github.com/caarlos0/log"
|
2024-05-26 15:02:57 -03:00
|
|
|
"github.com/goreleaser/goreleaser/v2/internal/artifact"
|
|
|
|
"github.com/goreleaser/goreleaser/v2/internal/pipe"
|
|
|
|
"github.com/goreleaser/goreleaser/v2/internal/semerrgroup"
|
|
|
|
"github.com/goreleaser/goreleaser/v2/internal/skips"
|
|
|
|
"github.com/goreleaser/goreleaser/v2/internal/tmpl"
|
|
|
|
"github.com/goreleaser/goreleaser/v2/pkg/config"
|
|
|
|
"github.com/goreleaser/goreleaser/v2/pkg/context"
|
2024-04-19 22:27:50 -03:00
|
|
|
)
|
|
|
|
|
|
|
|
type MacOS struct{}
|
|
|
|
|
|
|
|
func (MacOS) String() string { return "sign & notarize macOS binaries" }
|
|
|
|
|
|
|
|
func (MacOS) Skip(ctx *context.Context) bool {
|
|
|
|
return skips.Any(ctx, skips.Notarize) || len(ctx.Config.Notarize.MacOS) == 0
|
|
|
|
}
|
|
|
|
|
|
|
|
func (MacOS) Default(ctx *context.Context) error {
|
|
|
|
for i := range ctx.Config.Notarize.MacOS {
|
|
|
|
n := &ctx.Config.Notarize.MacOS[i]
|
|
|
|
if n.Notarize.Timeout == 0 {
|
|
|
|
n.Notarize.Timeout = 10 * time.Minute
|
|
|
|
}
|
|
|
|
if len(n.IDs) == 0 {
|
|
|
|
n.IDs = []string{ctx.Config.ProjectName}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (MacOS) Run(ctx *context.Context) error {
|
|
|
|
g := semerrgroup.NewSkipAware(semerrgroup.New(ctx.Parallelism))
|
|
|
|
for _, cfg := range ctx.Config.Notarize.MacOS {
|
|
|
|
g.Go(func() error {
|
|
|
|
return signAndNotarize(ctx, cfg)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
return g.Wait()
|
|
|
|
}
|
|
|
|
|
|
|
|
func signAndNotarize(ctx *context.Context, cfg config.MacOSSignNotarize) error {
|
|
|
|
ok, err := tmpl.New(ctx).Bool(cfg.Enabled)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("notarize: macos: %w", err)
|
|
|
|
}
|
|
|
|
if !ok {
|
|
|
|
return pipe.Skip("disabled")
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := tmpl.New(ctx).ApplyAll(
|
|
|
|
&cfg.Sign.Certificate,
|
|
|
|
&cfg.Sign.Password,
|
|
|
|
&cfg.Notarize.Key,
|
|
|
|
&cfg.Notarize.KeyID,
|
|
|
|
&cfg.Notarize.IssuerID,
|
|
|
|
); err != nil {
|
|
|
|
return fmt.Errorf("notarize: macos: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
p12, err := load.P12(cfg.Sign.Certificate, cfg.Sign.Password)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("notarize: macos: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
filters := []artifact.Filter{
|
|
|
|
artifact.ByGoos("darwin"),
|
|
|
|
artifact.Or(
|
|
|
|
artifact.ByType(artifact.Binary),
|
|
|
|
artifact.ByType(artifact.UniversalBinary),
|
|
|
|
),
|
|
|
|
}
|
|
|
|
if len(cfg.IDs) > 0 {
|
|
|
|
filters = append(filters, artifact.ByIDs(cfg.IDs...))
|
|
|
|
}
|
|
|
|
binaries := ctx.Artifacts.Filter(artifact.And(filters...))
|
|
|
|
if len(binaries.List()) == 0 {
|
|
|
|
return pipe.Skipf("no darwin binaries found with ids: %s", strings.Join(cfg.IDs, ", "))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, bin := range binaries.List() {
|
|
|
|
signCfg, err := quill.NewSigningConfigFromP12(bin.Path, *p12, true)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("notarize: macos: %s: %w", bin.Path, err)
|
|
|
|
}
|
|
|
|
signCfg = signCfg.WithTimestampServer("http://timestamp.apple.com/ts01")
|
|
|
|
|
|
|
|
log.WithField("binary", bin.Path).Info("signing")
|
|
|
|
if err := quill.Sign(*signCfg); err != nil {
|
|
|
|
return fmt.Errorf("notarize: macos: %s: %w", bin.Path, err)
|
|
|
|
}
|
|
|
|
|
2024-06-11 09:20:48 -03:00
|
|
|
if cfg.Notarize.IssuerID == "" ||
|
|
|
|
cfg.Notarize.KeyID == "" ||
|
|
|
|
cfg.Notarize.Key == "" {
|
|
|
|
log.WithField("binary", bin.Path).Info("will not try to notarize")
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2024-04-19 22:27:50 -03:00
|
|
|
notarizeCfg := quill.NewNotarizeConfig(
|
|
|
|
cfg.Notarize.IssuerID,
|
|
|
|
cfg.Notarize.KeyID,
|
|
|
|
cfg.Notarize.Key,
|
|
|
|
).WithStatusConfig(notary.StatusConfig{
|
|
|
|
Timeout: cfg.Notarize.Timeout,
|
|
|
|
Poll: 10,
|
|
|
|
Wait: cfg.Notarize.Wait,
|
|
|
|
})
|
|
|
|
|
|
|
|
if cfg.Notarize.Wait {
|
|
|
|
log.WithField("binary", bin.Path).Info("notarizing and waiting - this might take a while")
|
|
|
|
} else {
|
|
|
|
log.WithField("binary", bin.Path).Info("sending notarize request")
|
|
|
|
}
|
|
|
|
status, err := quill.Notarize(bin.Path, *notarizeCfg)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("notarize: macos: %s: %w", bin.Path, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
switch status {
|
|
|
|
case notary.AcceptedStatus:
|
|
|
|
log.WithField("binary", bin.Path).Info("notarized")
|
|
|
|
case notary.InvalidStatus:
|
|
|
|
return fmt.Errorf("notarize: macos: %s: invalid", bin.Path)
|
|
|
|
case notary.RejectedStatus:
|
|
|
|
return fmt.Errorf("notarize: macos: %s: rejected", bin.Path)
|
|
|
|
case notary.TimeoutStatus:
|
|
|
|
log.WithField("binary", bin.Path).Info("notarize timeout")
|
|
|
|
default:
|
|
|
|
log.WithField("binary", bin.Path).Info("notarize still pending")
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := binaries.Refresh(); err != nil {
|
|
|
|
return fmt.Errorf("notarize: macos: refresh artifacts: %w", err)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|