2026-05-01 23:56:02 +00:00
package config
import (
"fmt"
"strings"
)
// Config is the complete set of inputs to the action, parsed from env.
type Config struct {
WorkingDirectory string
AppName string
Version string
WailsVersion string
ExtraBuildFlags string
DeveloperIDCertBase64 string
DeveloperIDCertPassword string
NotarizationMethod string // "api-key" | "apple-id" | "auto"
NotarizationAPIKeyBase64 string
NotarizationAPIKeyID string
NotarizationAPIIssuerID string
NotarizationAppleID string
NotarizationApplePassword string
NotarizationTeamID string
S3Bucket string
S3Key string
S3EndpointURL string
S3Region string
2026-05-02 03:59:49 +00:00
S3ACL string
2026-05-01 23:56:02 +00:00
}
// Load reads the action's INPUT_* environment variables.
func Load ( get func ( string ) string ) * Config {
c := & Config {
WorkingDirectory : getOr ( get , "INPUT_WORKING_DIRECTORY" , "." ) ,
AppName : get ( "INPUT_APP_NAME" ) ,
Version : get ( "INPUT_VERSION" ) ,
WailsVersion : get ( "INPUT_WAILS_VERSION" ) ,
ExtraBuildFlags : get ( "INPUT_EXTRA_BUILD_FLAGS" ) ,
DeveloperIDCertBase64 : get ( "INPUT_DEVELOPER_ID_CERT_BASE64" ) ,
DeveloperIDCertPassword : get ( "INPUT_DEVELOPER_ID_CERT_PASSWORD" ) ,
NotarizationMethod : getOr ( get , "INPUT_NOTARIZATION_METHOD" , "auto" ) ,
NotarizationAPIKeyBase64 : get ( "INPUT_NOTARIZATION_API_KEY_BASE64" ) ,
NotarizationAPIKeyID : get ( "INPUT_NOTARIZATION_API_KEY_ID" ) ,
NotarizationAPIIssuerID : get ( "INPUT_NOTARIZATION_API_ISSUER_ID" ) ,
NotarizationAppleID : get ( "INPUT_NOTARIZATION_APPLE_ID" ) ,
NotarizationApplePassword : get ( "INPUT_NOTARIZATION_APPLE_PASSWORD" ) ,
NotarizationTeamID : get ( "INPUT_NOTARIZATION_TEAM_ID" ) ,
S3Bucket : get ( "INPUT_S3_BUCKET" ) ,
S3Key : get ( "INPUT_S3_KEY" ) ,
S3EndpointURL : get ( "INPUT_S3_ENDPOINT_URL" ) ,
S3Region : getOr ( get , "INPUT_S3_REGION" , "us-east-1" ) ,
2026-05-02 03:59:49 +00:00
S3ACL : get ( "INPUT_S3_ACL" ) ,
2026-05-01 23:56:02 +00:00
}
return c
}
func getOr ( get func ( string ) string , key , def string ) string {
if v := get ( key ) ; v != "" {
return v
}
return def
}
// Validate checks structural rules. It does NOT touch the filesystem.
func ( c * Config ) Validate ( ) error {
var missing [ ] string
if c . DeveloperIDCertBase64 == "" {
missing = append ( missing , "developer-id-cert-base64" )
}
if c . DeveloperIDCertPassword == "" {
missing = append ( missing , "developer-id-cert-password" )
}
if len ( missing ) > 0 {
return fmt . Errorf ( "missing required input(s): %s" , strings . Join ( missing , ", " ) )
}
apiFields := [ ] struct { name , value string } {
{ "notarization-api-key-base64" , c . NotarizationAPIKeyBase64 } ,
{ "notarization-api-key-id" , c . NotarizationAPIKeyID } ,
{ "notarization-api-issuer-id" , c . NotarizationAPIIssuerID } ,
}
appleFields := [ ] struct { name , value string } {
{ "notarization-apple-id" , c . NotarizationAppleID } ,
{ "notarization-apple-password" , c . NotarizationApplePassword } ,
{ "notarization-team-id" , c . NotarizationTeamID } ,
}
apiFilled , apiMissing := groupStatus ( apiFields )
appleFilled , appleMissing := groupStatus ( appleFields )
switch c . NotarizationMethod {
case "api-key" :
if ! apiFilled {
return fmt . Errorf ( "notarization-method=api-key requires: %s (missing: %s)" ,
joinNames ( apiFields ) , strings . Join ( apiMissing , ", " ) )
}
case "apple-id" :
if ! appleFilled {
return fmt . Errorf ( "notarization-method=apple-id requires: %s (missing: %s)" ,
joinNames ( appleFields ) , strings . Join ( appleMissing , ", " ) )
}
case "auto" , "" :
switch {
case apiFilled && appleFilled :
return fmt . Errorf ( "notarization credentials are ambiguous: both api-key and apple-id groups are populated; set notarization-method explicitly" )
case ! apiFilled && ! appleFilled :
return fmt . Errorf ( "no notarization credentials supplied: populate either the api-key group (%s) or the apple-id group (%s)" ,
joinNames ( apiFields ) , joinNames ( appleFields ) )
}
default :
return fmt . Errorf ( "notarization-method must be one of api-key, apple-id, auto (got %q)" , c . NotarizationMethod )
}
if c . S3Bucket != "" && c . S3Key == "" {
return fmt . Errorf ( "s3-bucket is set but s3-key is empty" )
}
2026-05-02 03:59:49 +00:00
if c . S3ACL != "" {
switch c . S3ACL {
case "private" , "public-read" , "public-read-write" , "authenticated-read" ,
"aws-exec-read" , "bucket-owner-read" , "bucket-owner-full-control" :
default :
return fmt . Errorf ( "s3-acl must be one of private, public-read, public-read-write, authenticated-read, aws-exec-read, bucket-owner-read, bucket-owner-full-control (got %q)" , c . S3ACL )
}
}
2026-05-01 23:56:02 +00:00
return nil
}
// ResolvedNotarizationMethod returns "api-key" or "apple-id" once Validate has succeeded.
func ( c * Config ) ResolvedNotarizationMethod ( ) string {
if c . NotarizationMethod == "api-key" || c . NotarizationMethod == "apple-id" {
return c . NotarizationMethod
}
if c . NotarizationAPIKeyID != "" {
return "api-key"
}
return "apple-id"
}
func groupStatus ( fields [ ] struct { name , value string } ) ( filled bool , missing [ ] string ) {
any := false
for _ , f := range fields {
if f . value != "" {
any = true
} else {
missing = append ( missing , f . name )
}
}
return any && len ( missing ) == 0 , missing
}
func joinNames ( fields [ ] struct { name , value string } ) string {
names := make ( [ ] string , len ( fields ) )
for i , f := range fields {
names [ i ] = f . name
}
return strings . Join ( names , ", " )
}