2017-09-12 20:01:12 -07:00
/ *
Package config provides a way to find and load SOPS configuration files
* /
2023-07-11 21:09:23 +02:00
package config //import "github.com/getsops/sops/v3/config"
2016-08-25 17:51:55 -07:00
import (
"fmt"
"os"
"path"
2021-04-12 08:29:06 -03:00
"path/filepath"
2016-08-25 17:51:55 -07:00
"regexp"
2021-04-12 08:29:06 -03:00
"strings"
2016-10-22 08:19:34 -07:00
2023-07-11 21:09:23 +02:00
"github.com/getsops/sops/v3"
"github.com/getsops/sops/v3/age"
"github.com/getsops/sops/v3/azkv"
"github.com/getsops/sops/v3/gcpkms"
2025-12-12 09:41:42 +03:00
"github.com/getsops/sops/v3/hckms"
2023-07-11 21:09:23 +02:00
"github.com/getsops/sops/v3/hcvault"
"github.com/getsops/sops/v3/kms"
"github.com/getsops/sops/v3/pgp"
"github.com/getsops/sops/v3/publish"
2025-09-07 17:37:00 +02:00
"go.yaml.in/yaml/v3"
2016-08-25 17:51:55 -07:00
)
type fileSystem interface {
Stat ( name string ) ( os . FileInfo , error )
}
type osFS struct {
stat func ( string ) ( os . FileInfo , error )
}
func ( fs osFS ) Stat ( name string ) ( os . FileInfo , error ) {
return fs . stat ( name )
}
var fs fileSystem = osFS { stat : os . Stat }
const (
2025-03-30 17:02:25 +02:00
maxDepth = 100
configFileName = ".sops.yaml"
alternateConfigName = ".sops.yml"
2016-08-25 17:51:55 -07:00
)
2025-03-30 17:02:25 +02:00
// ConfigFileResult contains the path to a config file and any warnings
type ConfigFileResult struct {
Path string
Warning string
}
// LookupConfigFile looks for a sops config file in the current working directory
// and on parent directories, up to the maxDepth limit.
// It returns a result containing the file path and any warnings.
func LookupConfigFile ( start string ) ( ConfigFileResult , error ) {
2016-08-25 17:51:55 -07:00
filepath := path . Dir ( start )
2025-03-30 17:02:25 +02:00
var foundAlternatePath string
2016-08-25 17:51:55 -07:00
for i := 0 ; i < maxDepth ; i ++ {
2025-03-30 14:53:57 +02:00
configPath := path . Join ( filepath , configFileName )
_ , err := fs . Stat ( configPath )
2025-03-30 17:02:25 +02:00
if err == nil {
result := ConfigFileResult { Path : configPath }
if foundAlternatePath != "" {
result . Warning = fmt . Sprintf (
"ignoring %q when searching for config file; the config file must be called %q; using %q instead" ,
foundAlternatePath , configFileName , configPath )
2025-03-30 14:53:57 +02:00
}
2025-03-30 17:02:25 +02:00
return result , nil
}
// Check for alternate filename if we haven't found one yet
if foundAlternatePath == "" {
alternatePath := path . Join ( filepath , alternateConfigName )
_ , altErr := fs . Stat ( alternatePath )
if altErr == nil {
foundAlternatePath = alternatePath
2025-03-30 14:53:57 +02:00
}
2016-08-25 17:51:55 -07:00
}
2025-03-30 17:02:25 +02:00
filepath = path . Join ( filepath , ".." )
2016-08-25 17:51:55 -07:00
}
2025-03-30 17:02:25 +02:00
// No config file found
result := ConfigFileResult { }
if foundAlternatePath != "" {
result . Warning = fmt . Sprintf (
"ignoring %q when searching for config file; the config file must be called %q" ,
foundAlternatePath , configFileName )
2025-03-30 14:53:57 +02:00
}
2025-03-30 17:02:25 +02:00
return result , fmt . Errorf ( "config file not found" )
2025-03-30 14:53:57 +02:00
}
// FindConfigFile looks for a sops config file in the current working directory and on parent directories, up to the limit defined by the maxDepth constant.
func FindConfigFile ( start string ) ( string , error ) {
2025-03-30 17:02:25 +02:00
result , err := LookupConfigFile ( start )
return result . Path , err
2016-08-25 17:51:55 -07:00
}
2021-09-02 16:13:03 -07:00
type DotenvStoreConfig struct { }
type INIStoreConfig struct { }
2023-11-14 07:27:47 +01:00
type JSONStoreConfig struct {
2023-09-14 08:41:23 +02:00
Indent int ` yaml:"indent" `
}
2021-09-02 16:13:03 -07:00
2023-11-14 07:27:47 +01:00
type JSONBinaryStoreConfig struct {
Indent int ` yaml:"indent" `
}
2021-09-02 16:13:03 -07:00
type YAMLStoreConfig struct {
Indent int ` yaml:"indent" `
}
type StoresConfig struct {
Dotenv DotenvStoreConfig ` yaml:"dotenv" `
INI INIStoreConfig ` yaml:"ini" `
JSONBinary JSONBinaryStoreConfig ` yaml:"json_binary" `
JSON JSONStoreConfig ` yaml:"json" `
YAML YAMLStoreConfig ` yaml:"yaml" `
}
2016-08-25 17:51:55 -07:00
type configFile struct {
2019-06-27 16:48:54 +00:00
CreationRules [ ] creationRule ` yaml:"creation_rules" `
DestinationRules [ ] destinationRule ` yaml:"destination_rules" `
2021-09-02 16:13:03 -07:00
Stores StoresConfig ` yaml:"stores" `
2016-08-25 17:51:55 -07:00
}
2017-08-24 17:24:04 -07:00
type keyGroup struct {
2025-09-12 22:23:29 +02:00
Merge [ ] keyGroup ` yaml:"merge" `
KMS [ ] kmsKey ` yaml:"kms" `
2018-06-17 22:50:30 +02:00
GCPKMS [ ] gcpKmsKey ` yaml:"gcp_kms" `
2025-12-12 09:41:42 +03:00
HCKms [ ] hckmsKey ` yaml:"hckms" `
2018-06-17 22:50:30 +02:00
AzureKV [ ] azureKVKey ` yaml:"azure_keyvault" `
2020-05-05 00:57:51 +05:30
Vault [ ] string ` yaml:"hc_vault" `
2020-08-07 01:58:17 -07:00
Age [ ] string ` yaml:"age" `
2025-09-12 22:23:29 +02:00
PGP [ ] string ` yaml:"pgp" `
2017-09-15 14:27:04 -07:00
}
type gcpKmsKey struct {
ResourceID string ` yaml:"resource_id" `
2017-09-12 11:38:03 -07:00
}
type kmsKey struct {
2019-01-25 12:42:41 +00:00
Arn string ` yaml:"arn" `
Role string ` yaml:"role,omitempty" `
Context map [ string ] * string ` yaml:"context" `
AwsProfile string ` yaml:"aws_profile" `
2017-08-24 17:24:04 -07:00
}
2018-06-17 22:50:30 +02:00
type azureKVKey struct {
VaultURL string ` yaml:"vaultUrl" `
Key string ` yaml:"key" `
Version string ` yaml:"version" `
}
2025-12-12 09:41:42 +03:00
type hckmsKey struct {
KeyID string ` yaml:"key_id" `
}
2019-06-27 16:48:54 +00:00
type destinationRule struct {
2019-08-30 13:44:04 -07:00
PathRegex string ` yaml:"path_regex" `
S3Bucket string ` yaml:"s3_bucket" `
S3Prefix string ` yaml:"s3_prefix" `
GCSBucket string ` yaml:"gcs_bucket" `
GCSPrefix string ` yaml:"gcs_prefix" `
VaultPath string ` yaml:"vault_path" `
VaultAddress string ` yaml:"vault_address" `
VaultKVMountName string ` yaml:"vault_kv_mount_name" `
VaultKVVersion int ` yaml:"vault_kv_version" `
RecreationRule creationRule ` yaml:"recreation_rule,omitempty" `
2020-01-09 09:18:51 +06:00
OmitExtensions bool ` yaml:"omit_extensions" `
2019-06-27 16:48:54 +00:00
}
2016-08-25 17:51:55 -07:00
type creationRule struct {
2025-06-24 00:10:21 -06:00
PathRegex string ` yaml:"path_regex" `
KMS interface { } ` yaml:"kms" ` // string or []string
AwsProfile string ` yaml:"aws_profile" `
Age interface { } ` yaml:"age" ` // string or []string
PGP interface { } ` yaml:"pgp" ` // string or []string
GCPKMS interface { } ` yaml:"gcp_kms" ` // string or []string
2025-12-13 23:23:56 +03:00
HCKms [ ] string ` yaml:"hckms" `
2025-06-24 00:10:21 -06:00
AzureKeyVault interface { } ` yaml:"azure_keyvault" ` // string or []string
VaultURI interface { } ` yaml:"hc_vault_transit_uri" ` // string or []string
KeyGroups [ ] keyGroup ` yaml:"key_groups" `
ShamirThreshold int ` yaml:"shamir_threshold" `
UnencryptedSuffix string ` yaml:"unencrypted_suffix" `
EncryptedSuffix string ` yaml:"encrypted_suffix" `
UnencryptedRegex string ` yaml:"unencrypted_regex" `
EncryptedRegex string ` yaml:"encrypted_regex" `
UnencryptedCommentRegex string ` yaml:"unencrypted_comment_regex" `
EncryptedCommentRegex string ` yaml:"encrypted_comment_regex" `
MACOnlyEncrypted bool ` yaml:"mac_only_encrypted" `
}
// Helper methods to safely extract keys as []string
2025-06-24 00:10:21 -06:00
func ( c * creationRule ) GetKMSKeys ( ) ( [ ] string , error ) {
2025-07-21 16:05:32 -06:00
return parseKeyField ( c . KMS , "kms" )
2025-06-24 00:10:21 -06:00
}
2025-06-24 00:10:21 -06:00
func ( c * creationRule ) GetAgeKeys ( ) ( [ ] string , error ) {
2025-07-21 16:05:32 -06:00
return parseKeyField ( c . Age , "age" )
2025-06-24 00:10:21 -06:00
}
2025-06-24 00:10:21 -06:00
func ( c * creationRule ) GetPGPKeys ( ) ( [ ] string , error ) {
2025-07-21 16:05:32 -06:00
return parseKeyField ( c . PGP , "pgp" )
2025-06-24 00:10:21 -06:00
}
2025-06-24 00:10:21 -06:00
func ( c * creationRule ) GetGCPKMSKeys ( ) ( [ ] string , error ) {
2025-07-21 16:05:32 -06:00
return parseKeyField ( c . GCPKMS , "gcp_kms" )
2025-06-24 00:10:21 -06:00
}
2025-06-24 00:10:21 -06:00
func ( c * creationRule ) GetAzureKeyVaultKeys ( ) ( [ ] string , error ) {
2025-07-21 16:05:32 -06:00
return parseKeyField ( c . AzureKeyVault , "azure_keyvault" )
2025-06-24 00:10:21 -06:00
}
2025-06-24 00:10:21 -06:00
func ( c * creationRule ) GetVaultURIs ( ) ( [ ] string , error ) {
2025-07-21 16:05:32 -06:00
return parseKeyField ( c . VaultURI , "hc_vault_transit_uri" )
2025-06-24 00:10:21 -06:00
}
2025-12-12 09:41:42 +03:00
func ( c * creationRule ) GetHckmsKeys ( ) ( [ ] string , error ) {
2025-12-13 23:19:07 +03:00
return c . HCKms , nil
2025-12-12 09:41:42 +03:00
}
2025-06-24 00:10:21 -06:00
// Utility function to handle both string and []string
2025-07-21 16:05:32 -06:00
func parseKeyField ( field interface { } , fieldName string ) ( [ ] string , error ) {
if field == nil {
return [ ] string { } , nil
}
2025-06-24 00:10:21 -06:00
switch v := field . ( type ) {
case string :
if v == "" {
2025-06-24 00:10:21 -06:00
return [ ] string { } , nil
2025-06-24 00:10:21 -06:00
}
// Existing CSV parsing logic
keys := strings . Split ( v , "," )
result := make ( [ ] string , 0 , len ( keys ) )
for _ , key := range keys {
trimmed := strings . TrimSpace ( key )
if trimmed != "" { // Skip empty strings (fixes trailing comma issue)
result = append ( result , trimmed )
}
}
2025-06-24 00:10:21 -06:00
return result , nil
2025-06-24 00:10:21 -06:00
case [ ] interface { } :
result := make ( [ ] string , len ( v ) )
for i , item := range v {
2025-07-21 16:05:32 -06:00
if str , ok := item . ( string ) ; ok {
result [ i ] = str
} else {
return nil , fmt . Errorf ( "invalid %s key configuration: expected string in list, got %T" , fieldName , item )
}
2025-06-24 00:10:21 -06:00
}
2025-06-24 00:10:21 -06:00
return result , nil
2025-06-24 00:10:21 -06:00
case [ ] string :
2025-06-24 00:10:21 -06:00
return v , nil
2025-06-24 00:10:21 -06:00
default :
2025-07-21 16:05:32 -06:00
return nil , fmt . Errorf ( "invalid %s key configuration: expected string, []string, or nil, got %T" , fieldName , field )
2025-06-24 00:10:21 -06:00
}
2016-08-25 17:51:55 -07:00
}
2023-11-14 07:27:47 +01:00
func NewStoresConfig ( ) * StoresConfig {
storesConfig := & StoresConfig { }
2023-09-14 20:41:56 +02:00
storesConfig . JSON . Indent = - 1
2023-11-14 07:27:47 +01:00
storesConfig . JSONBinary . Indent = - 1
2023-09-14 20:41:56 +02:00
return storesConfig
}
2016-08-25 17:51:55 -07:00
// Load loads a sops config file into a temporary struct
func ( f * configFile ) load ( bytes [ ] byte ) error {
err := yaml . Unmarshal ( bytes , f )
if err != nil {
return fmt . Errorf ( "Could not unmarshal config file: %s" , err )
}
return nil
}
2017-09-12 13:53:21 -07:00
// Config is the configuration for a given SOPS file
type Config struct {
2021-12-20 00:03:19 +01:00
KeyGroups [ ] sops . KeyGroup
ShamirThreshold int
UnencryptedSuffix string
EncryptedSuffix string
UnencryptedRegex string
EncryptedRegex string
UnencryptedCommentRegex string
EncryptedCommentRegex string
MACOnlyEncrypted bool
Destination publish . Destination
OmitExtensions bool
2017-09-12 13:53:21 -07:00
}
2024-04-23 17:20:39 +02:00
func deduplicateKeygroup ( group sops . KeyGroup ) sops . KeyGroup {
var deduplicatedKeygroup sops . KeyGroup
unique := make ( map [ string ] bool )
for _ , v := range group {
key := fmt . Sprintf ( "%T/%v" , v , v . ToString ( ) )
if _ , ok := unique [ key ] ; ok {
// key already contained, therefore not unique
continue
}
deduplicatedKeygroup = append ( deduplicatedKeygroup , v )
unique [ key ] = true
}
return deduplicatedKeygroup
}
func extractMasterKeys ( group keyGroup ) ( sops . KeyGroup , error ) {
var keyGroup sops . KeyGroup
for _ , k := range group . Merge {
subKeyGroup , err := extractMasterKeys ( k )
if err != nil {
return nil , err
}
keyGroup = append ( keyGroup , subKeyGroup ... )
}
for _ , k := range group . Age {
keys , err := age . MasterKeysFromRecipients ( k )
if err != nil {
return nil , err
}
for _ , key := range keys {
keyGroup = append ( keyGroup , key )
}
}
for _ , k := range group . PGP {
keyGroup = append ( keyGroup , pgp . NewMasterKeyFromFingerprint ( k ) )
}
for _ , k := range group . KMS {
keyGroup = append ( keyGroup , kms . NewMasterKeyWithProfile ( k . Arn , k . Role , k . Context , k . AwsProfile ) )
}
for _ , k := range group . GCPKMS {
keyGroup = append ( keyGroup , gcpkms . NewMasterKeyFromResourceID ( k . ResourceID ) )
}
2025-12-12 09:41:42 +03:00
for _ , k := range group . HCKms {
key , err := hckms . NewMasterKey ( k . KeyID )
if err != nil {
return nil , err
}
keyGroup = append ( keyGroup , key )
}
2024-04-23 17:20:39 +02:00
for _ , k := range group . AzureKV {
2025-09-27 10:35:15 +02:00
if key , err := azkv . NewMasterKeyWithOptionalVersion ( k . VaultURL , k . Key , k . Version ) ; err == nil {
2025-09-12 22:30:05 +02:00
keyGroup = append ( keyGroup , key )
} else {
return nil , err
}
2024-04-23 17:20:39 +02:00
}
for _ , k := range group . Vault {
if masterKey , err := hcvault . NewMasterKeyFromURI ( k ) ; err == nil {
keyGroup = append ( keyGroup , masterKey )
} else {
return nil , err
}
}
return deduplicateKeygroup ( keyGroup ) , nil
}
2025-06-24 00:10:21 -06:00
func getKeysWithValidation ( getKeysFunc func ( ) ( [ ] string , error ) , keyType string ) ( [ ] string , error ) {
keys , err := getKeysFunc ( )
if err != nil {
return nil , fmt . Errorf ( "invalid %s key configuration: %w" , keyType , err )
}
return keys , nil
}
2019-06-27 16:48:54 +00:00
func getKeyGroupsFromCreationRule ( cRule * creationRule , kmsEncryptionContext map [ string ] * string ) ( [ ] sops . KeyGroup , error ) {
2017-08-24 17:24:04 -07:00
var groups [ ] sops . KeyGroup
2019-06-27 16:48:54 +00:00
if len ( cRule . KeyGroups ) > 0 {
for _ , group := range cRule . KeyGroups {
2024-04-23 17:20:39 +02:00
keyGroup , err := extractMasterKeys ( group )
if err != nil {
return nil , err
2020-05-05 00:57:51 +05:30
}
2017-09-12 13:53:21 -07:00
groups = append ( groups , keyGroup )
}
} else {
var keyGroup sops . KeyGroup
2025-06-24 00:10:21 -06:00
ageKeys , err := getKeysWithValidation ( cRule . GetAgeKeys , "age" )
if err != nil {
return nil , err
}
2025-07-21 16:05:32 -06:00
if len ( ageKeys ) > 0 {
2025-06-24 00:10:21 -06:00
ageKeys , err := age . MasterKeysFromRecipients ( strings . Join ( ageKeys , "," ) )
2020-08-16 15:12:54 -07:00
if err != nil {
return nil , err
} else {
for _ , ak := range ageKeys {
keyGroup = append ( keyGroup , ak )
}
2020-08-07 01:58:17 -07:00
}
}
2025-06-24 00:10:21 -06:00
pgpKeys , err := getKeysWithValidation ( cRule . GetPGPKeys , "pgp" )
if err != nil {
return nil , err
}
for _ , k := range pgp . MasterKeysFromFingerprintString ( strings . Join ( pgpKeys , "," ) ) {
2017-09-12 13:53:21 -07:00
keyGroup = append ( keyGroup , k )
}
2025-06-24 00:10:21 -06:00
kmsKeys , err := getKeysWithValidation ( cRule . GetKMSKeys , "kms" )
if err != nil {
return nil , err
}
for _ , k := range kms . MasterKeysFromArnString ( strings . Join ( kmsKeys , "," ) , kmsEncryptionContext , cRule . AwsProfile ) {
2017-09-12 13:53:21 -07:00
keyGroup = append ( keyGroup , k )
2016-08-25 17:51:55 -07:00
}
2025-06-24 00:10:21 -06:00
gcpkmsKeys , err := getKeysWithValidation ( cRule . GetGCPKMSKeys , "gcpkms" )
if err != nil {
return nil , err
}
for _ , k := range gcpkms . MasterKeysFromResourceIDString ( strings . Join ( gcpkmsKeys , "," ) ) {
2017-09-15 14:27:04 -07:00
keyGroup = append ( keyGroup , k )
}
2025-12-12 09:41:42 +03:00
hckmsKeys , err := getKeysWithValidation ( cRule . GetHckmsKeys , "hckms" )
if err != nil {
return nil , err
}
hckmsMasterKeys , err := hckms . NewMasterKeyFromKeyIDString ( strings . Join ( hckmsKeys , "," ) )
if err != nil {
return nil , err
}
for _ , k := range hckmsMasterKeys {
keyGroup = append ( keyGroup , k )
}
2025-07-21 16:05:32 -06:00
azKeys , err := getKeysWithValidation ( cRule . GetAzureKeyVaultKeys , "azure_keyvault" )
2025-06-24 00:10:21 -06:00
if err != nil {
return nil , err
}
azureKeys , err := azkv . MasterKeysFromURLs ( strings . Join ( azKeys , "," ) )
2018-06-18 16:03:24 +02:00
if err != nil {
return nil , err
}
for _ , k := range azureKeys {
2018-06-17 22:50:30 +02:00
keyGroup = append ( keyGroup , k )
}
2025-06-24 00:10:21 -06:00
vaultKeyUris , err := getKeysWithValidation ( cRule . GetVaultURIs , "vault" )
if err != nil {
return nil , err
}
vaultKeys , err := hcvault . NewMasterKeysFromURIs ( strings . Join ( vaultKeyUris , "," ) )
2020-05-05 00:57:51 +05:30
if err != nil {
return nil , err
}
for _ , k := range vaultKeys {
keyGroup = append ( keyGroup , k )
}
2017-09-12 13:53:21 -07:00
groups = append ( groups , keyGroup )
}
2019-06-27 16:48:54 +00:00
return groups , nil
}
func loadConfigFile ( confPath string ) ( * configFile , error ) {
2023-08-14 23:35:54 +02:00
confBytes , err := os . ReadFile ( confPath )
2019-06-27 16:48:54 +00:00
if err != nil {
return nil , fmt . Errorf ( "could not read config file: %s" , err )
}
conf := & configFile { }
2023-09-14 20:41:56 +02:00
conf . Stores = * NewStoresConfig ( )
2019-06-27 16:48:54 +00:00
err = conf . load ( confBytes )
if err != nil {
return nil , fmt . Errorf ( "error loading config: %s" , err )
}
return conf , nil
}
func configFromRule ( rule * creationRule , kmsEncryptionContext map [ string ] * string ) ( * Config , error ) {
2019-08-14 15:39:21 -04:00
cryptRuleCount := 0
if rule . UnencryptedSuffix != "" {
cryptRuleCount ++
}
if rule . EncryptedSuffix != "" {
cryptRuleCount ++
}
2023-09-22 11:20:35 +02:00
if rule . UnencryptedRegex != "" {
cryptRuleCount ++
}
2019-08-14 15:39:21 -04:00
if rule . EncryptedRegex != "" {
cryptRuleCount ++
}
2021-12-20 00:03:19 +01:00
if rule . UnencryptedCommentRegex != "" {
cryptRuleCount ++
}
if rule . EncryptedCommentRegex != "" {
cryptRuleCount ++
}
2019-08-14 15:39:21 -04:00
if cryptRuleCount > 1 {
2021-12-20 00:03:19 +01:00
return nil , fmt . Errorf ( "error loading config: cannot use more than one of encrypted_suffix, unencrypted_suffix, encrypted_regex, unencrypted_regex, encrypted_comment_regex, or unencrypted_comment_regex for the same rule" )
2019-06-27 16:48:54 +00:00
}
groups , err := getKeyGroupsFromCreationRule ( rule , kmsEncryptionContext )
if err != nil {
return nil , err
}
2017-09-12 13:53:21 -07:00
return & Config {
2021-12-20 00:03:19 +01:00
KeyGroups : groups ,
ShamirThreshold : rule . ShamirThreshold ,
UnencryptedSuffix : rule . UnencryptedSuffix ,
EncryptedSuffix : rule . EncryptedSuffix ,
UnencryptedRegex : rule . UnencryptedRegex ,
EncryptedRegex : rule . EncryptedRegex ,
UnencryptedCommentRegex : rule . UnencryptedCommentRegex ,
EncryptedCommentRegex : rule . EncryptedCommentRegex ,
MACOnlyEncrypted : rule . MACOnlyEncrypted ,
2017-09-12 13:53:21 -07:00
} , nil
}
2019-06-27 16:48:54 +00:00
func parseDestinationRuleForFile ( conf * configFile , filePath string , kmsEncryptionContext map [ string ] * string ) ( * Config , error ) {
var rule * creationRule
var dRule * destinationRule
if len ( conf . DestinationRules ) > 0 {
for _ , r := range conf . DestinationRules {
if r . PathRegex == "" {
dRule = & r
rule = & dRule . RecreationRule
break
}
if r . PathRegex != "" {
if match , _ := regexp . MatchString ( r . PathRegex , filePath ) ; match {
dRule = & r
rule = & dRule . RecreationRule
break
}
}
}
}
if dRule == nil {
return nil , fmt . Errorf ( "error loading config: no matching destination found in config" )
}
var dest publish . Destination
2025-09-07 14:50:00 -05:00
destinationCount := 0
if dRule . S3Bucket != "" {
destinationCount ++
}
if dRule . GCSBucket != "" {
destinationCount ++
}
if dRule . VaultPath != "" {
destinationCount ++
}
if destinationCount > 1 {
2024-11-25 22:53:11 +01:00
return nil , fmt . Errorf ( "error loading config: more than one destinations were found in a single destination rule, you can only use one per rule" )
}
if dRule . S3Bucket != "" {
dest = publish . NewS3Destination ( dRule . S3Bucket , dRule . S3Prefix )
}
if dRule . GCSBucket != "" {
dest = publish . NewGCSDestination ( dRule . GCSBucket , dRule . GCSPrefix )
}
if dRule . VaultPath != "" {
dest = publish . NewVaultDestination ( dRule . VaultAddress , dRule . VaultPath , dRule . VaultKVMountName , dRule . VaultKVVersion )
2019-06-27 16:48:54 +00:00
}
config , err := configFromRule ( rule , kmsEncryptionContext )
if err != nil {
return nil , err
}
config . Destination = dest
2020-01-09 09:18:51 +06:00
config . OmitExtensions = dRule . OmitExtensions
2019-06-27 16:48:54 +00:00
return config , nil
}
2021-04-12 08:29:06 -03:00
func parseCreationRuleForFile ( conf * configFile , confPath , filePath string , kmsEncryptionContext map [ string ] * string ) ( * Config , error ) {
2020-04-24 23:54:06 +02:00
// If config file doesn't contain CreationRules (it's empty or only contains DestionationRules), assume it does not exist
if conf . CreationRules == nil {
return nil , nil
}
2021-04-12 08:29:06 -03:00
configDir , err := filepath . Abs ( filepath . Dir ( confPath ) )
if err != nil {
return nil , err
}
// compare file path relative to path of config file
2023-08-14 23:35:54 +02:00
filePath = strings . TrimPrefix ( filePath , configDir + string ( filepath . Separator ) )
2021-04-12 08:29:06 -03:00
2019-06-27 16:48:54 +00:00
var rule * creationRule
for _ , r := range conf . CreationRules {
if r . PathRegex == "" {
rule = & r
break
}
2021-03-10 15:23:11 -05:00
reg , err := regexp . Compile ( r . PathRegex )
if err != nil {
return nil , fmt . Errorf ( "can not compile regexp: %w" , err )
}
if reg . MatchString ( filePath ) {
rule = & r
break
2019-06-27 16:48:54 +00:00
}
}
if rule == nil {
return nil , fmt . Errorf ( "error loading config: no matching creation rules found" )
}
config , err := configFromRule ( rule , kmsEncryptionContext )
if err != nil {
return nil , err
}
return config , nil
}
2020-05-04 22:58:45 +02:00
// LoadCreationRuleForFile load the configuration for a given SOPS file from the config file at confPath. A kmsEncryptionContext
2017-09-12 13:53:21 -07:00
// should be provided for configurations that do not contain key groups, as there's no way to specify context inside
// a SOPS config file outside of key groups.
2020-05-04 22:58:45 +02:00
func LoadCreationRuleForFile ( confPath string , filePath string , kmsEncryptionContext map [ string ] * string ) ( * Config , error ) {
2019-06-27 16:48:54 +00:00
conf , err := loadConfigFile ( confPath )
2017-09-12 13:53:21 -07:00
if err != nil {
2019-06-27 16:48:54 +00:00
return nil , err
}
2021-04-12 08:29:06 -03:00
return parseCreationRuleForFile ( conf , confPath , filePath , kmsEncryptionContext )
2019-06-27 16:48:54 +00:00
}
2020-05-04 22:58:45 +02:00
// LoadDestinationRuleForFile works the same as LoadCreationRuleForFile, but gets the "creation_rule" from the matching destination_rule's
2019-06-27 16:48:54 +00:00
// "recreation_rule".
func LoadDestinationRuleForFile ( confPath string , filePath string , kmsEncryptionContext map [ string ] * string ) ( * Config , error ) {
conf , err := loadConfigFile ( confPath )
if err != nil {
return nil , err
2016-08-25 17:51:55 -07:00
}
2019-06-27 16:48:54 +00:00
return parseDestinationRuleForFile ( conf , filePath , kmsEncryptionContext )
2016-08-25 17:51:55 -07:00
}
2021-09-02 16:13:03 -07:00
func LoadStoresConfig ( confPath string ) ( * StoresConfig , error ) {
conf , err := loadConfigFile ( confPath )
if err != nil {
return nil , err
}
return & conf . Stores , nil
}