cli/pkg/build/signing/signer.go
Snider 552feb9d45 Migrate pkg/build to io.Medium abstraction (#287)
* chore(io): Migrate pkg/build to Medium abstraction

- Updated io.Medium interface with Open() and Create() methods to support streaming.
- Migrated pkg/build, pkg/build/builders, and pkg/build/signing to use io.Medium.
- Added FS field to build.Config and updated build.Builder interface.
- Refactored checksum and archive logic to use io.Medium streaming.
- Updated pkg/release and pkg/build/buildcmd to use io.Local.
- Updated unit tests to match new signatures.

* chore(io): Migrate pkg/build to Medium abstraction (fix CI)

- Fixed formatting in pkg/build/builders/wails.go.
- Fixed TestLoadConfig_Testdata and TestDiscover_Testdata to use absolute paths with io.Local to ensure compatibility with GitHub CI.
- Verified that all build and release tests pass.

* chore(io): Migrate pkg/build to Medium abstraction (fix CI paths)

- Ensured that outputDir and configPath are absolute in runProjectBuild.
- Fixed TestLoadConfig_Testdata and TestDiscover_Testdata to use absolute paths correctly.
- Verified that all build and release tests pass locally.

* chore(io): Migrate pkg/build to Medium abstraction (final fix)

- Improved io.Local to handle relative paths relative to CWD when rooted at "/".
- This makes io.Local a drop-in replacement for the 'os' package for most use cases.
- Ensured absolute paths are used in build logic and tests where appropriate.
- Fixed formatting and cleaned up debug prints.

* chore(io): address code review and fix CI

- Fix MockFile.Read to return io.EOF
- Use filepath.Match in TaskfileBuilder for precise globbing
- Stream xz data in createTarXzArchive to avoid in-memory string conversion
- Fix TestPath_RootFilesystem in local medium tests
- Fix formatting in pkg/build/buildcmd/cmd_project.go

* chore(io): resolve merge conflicts and final migration of pkg/build

- Resolved merge conflicts in pkg/io/io.go, pkg/io/local/client.go, and pkg/release/release.go.
- Reconciled io.Medium interface with upstream changes (unifying to fs.File for Open).
- Integrated upstream validatePath logic into the local medium.
- Completed migration of pkg/build and related packages to io.Medium.
- Addressed previous code review feedback on MockMedium and TaskfileBuilder.

* chore(io): resolve merge conflicts and finalize migration

- Resolved merge conflicts with dev branch.
- Unified io.Medium interface (Open returns fs.File, Create returns io.WriteCloser).
- Integrated upstream validatePath logic.
- Ensured all tests pass across pkg/io, pkg/build, and pkg/release.

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 17:59:10 +00:00

83 lines
2.5 KiB
Go

// Package signing provides code signing for build artifacts.
package signing
import (
"context"
"os"
"strings"
"github.com/host-uk/core/pkg/io"
)
// 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, fs io.Medium, 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
}