From 186127490961e954f66e1d5cb051f48b3a74e743 Mon Sep 17 00:00:00 2001 From: Snider Date: Thu, 29 Jan 2026 02:46:08 +0000 Subject: [PATCH] feat(signing): add Signer interface and config types Defines interface for GPG, macOS, and Windows signing. Config supports env var expansion for secrets. Co-Authored-By: Claude Opus 4.5 --- pkg/build/signing/signer.go | 81 +++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 pkg/build/signing/signer.go diff --git a/pkg/build/signing/signer.go b/pkg/build/signing/signer.go new file mode 100644 index 0000000..80213a9 --- /dev/null +++ b/pkg/build/signing/signer.go @@ -0,0 +1,81 @@ +// Package signing provides code signing for build artifacts. +package signing + +import ( + "context" + "os" + "strings" +) + +// Signer defines the interface for code signing implementations. +type Signer interface { + // Name returns the signer's identifier. + Name() string + // Available checks if this signer can be used. + Available() bool + // Sign signs the artifact at the given path. + Sign(ctx context.Context, path string) error +} + +// SignConfig holds signing configuration from .core/build.yaml. +type SignConfig struct { + Enabled bool `yaml:"enabled"` + GPG GPGConfig `yaml:"gpg,omitempty"` + MacOS MacOSConfig `yaml:"macos,omitempty"` + Windows WindowsConfig `yaml:"windows,omitempty"` +} + +// GPGConfig holds GPG signing configuration. +type GPGConfig struct { + Key string `yaml:"key"` // Key ID or fingerprint, supports $ENV +} + +// MacOSConfig holds macOS codesign configuration. +type MacOSConfig struct { + Identity string `yaml:"identity"` // Developer ID Application: ... + Notarize bool `yaml:"notarize"` // Submit to Apple for notarization + AppleID string `yaml:"apple_id"` // Apple account email + TeamID string `yaml:"team_id"` // Team ID + AppPassword string `yaml:"app_password"` // App-specific password +} + +// WindowsConfig holds Windows signtool configuration (placeholder). +type WindowsConfig struct { + Certificate string `yaml:"certificate"` // Path to .pfx + Password string `yaml:"password"` // Certificate password +} + +// DefaultSignConfig returns sensible defaults. +func DefaultSignConfig() SignConfig { + return SignConfig{ + Enabled: true, + GPG: GPGConfig{ + Key: os.Getenv("GPG_KEY_ID"), + }, + MacOS: MacOSConfig{ + Identity: os.Getenv("CODESIGN_IDENTITY"), + AppleID: os.Getenv("APPLE_ID"), + TeamID: os.Getenv("APPLE_TEAM_ID"), + AppPassword: os.Getenv("APPLE_APP_PASSWORD"), + }, + } +} + +// ExpandEnv expands environment variables in config values. +func (c *SignConfig) ExpandEnv() { + c.GPG.Key = expandEnv(c.GPG.Key) + c.MacOS.Identity = expandEnv(c.MacOS.Identity) + c.MacOS.AppleID = expandEnv(c.MacOS.AppleID) + c.MacOS.TeamID = expandEnv(c.MacOS.TeamID) + c.MacOS.AppPassword = expandEnv(c.MacOS.AppPassword) + c.Windows.Certificate = expandEnv(c.Windows.Certificate) + c.Windows.Password = expandEnv(c.Windows.Password) +} + +// expandEnv expands $VAR or ${VAR} in a string. +func expandEnv(s string) string { + if strings.HasPrefix(s, "$") { + return os.ExpandEnv(s) + } + return s +}