diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0d96566450..f1a1a0340f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -42,20 +42,20 @@ jobs: uses: sigstore/cosign-installer@11086d25041f77fe8fe7b9ea4e48e3b9192b8f19 # v3.1.2 - name: Setup QEMU - uses: docker/setup-qemu-action@2b82ce82d56a2a04d2637cd93a637ae1b359c0a7 # v2.2.0 + uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # v3.0.0 - name: Setup Docker Buildx - uses: docker/setup-buildx-action@885d1462b80bc1c1c7f0b00334ad271f09369c55 # v2.10.0 + uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 - name: Login to GitHub Container Registry - uses: docker/login-action@465a07811f14bebb1938fbed4728c6a1ff8901fc # v2.2.0 + uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Login to Quay.io - uses: docker/login-action@465a07811f14bebb1938fbed4728c6a1ff8901fc # v2.2.0 + uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 with: registry: quay.io username: ${{ secrets.QUAY_BOT_USERNAME }} diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5cf264db33..f119dcbb21 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,8 +1,8 @@ Changelog ========= -3.8.0-rc.1 ----------- +3.8.0 +----- Features: * Support ``--version`` without network requests using ``--disable-version-check`` (#1115) @@ -10,7 +10,7 @@ Features: Improvements: -* pgp: modernize and improve, and add tests (#1054) +* pgp: modernize and improve, and add tests (#1054, #1282) * azkv: update SDK to latest, add tests, tidy (#1067, #1092, #1256) * age: improve identity loading, add tests, tidy (#1064) * kms: AWS SDK V2, allow creds config, add tests (#1065, #1257) @@ -19,15 +19,15 @@ Improvements: * Do not report version when upstream ``--version`` check fails (#1124) * Use GitHub endpoints in ``--version`` command (#1261) * Close temporary file before invoking editor to widen support on Windows (#1265) -* Update dependencies (#1063, #1091, #1147, #1242, #1260, #1264) +* Update dependencies (#1063, #1091, #1147, #1242, #1260, #1264, #1275, #1280, #1283) * Deal with various deprecations of dependencies (#1113, #1262) Bug fixes: * Ensure YAML comments are not displaced (#1069) * Ensure default Google credentials can be used again after introduction of ``GOOGLE_CREDENTIALS`` (#1249) -* Avoid duplicate logging of errors in some key sources (#1146) -* Using `--set` on a root level key does no longer truncate existing values (#899) +* Avoid duplicate logging of errors in some key sources (#1146, #1281) +* Using ``--set`` on a root level key does no longer truncate existing values (#899) * Ensure stable order of SOPS parameters in dotenv file (#1101) Project changes: @@ -45,6 +45,10 @@ Project changes: * Improve Make targets and address various issues (#1258) * Ensure clean working tree in CI (#1267) * Fix CHANGELOG.rst formatting (#1269) +* Pin GitHub Actions to full length commit SHA and add CodeQL (#1276) +* Enable Dependabot for Docker, GitHub Actions and Go Mod (#1277) +* Generate versioned ``.intoto.jsonl`` (#1278) +* Update CI dependencies (#1279) 3.7.3 ----- diff --git a/age/keysource.go b/age/keysource.go index 837333e174..a83d1a5c22 100644 --- a/age/keysource.go +++ b/age/keysource.go @@ -11,8 +11,8 @@ import ( "filippo.io/age" "filippo.io/age/armor" - "github.com/sirupsen/logrus" "github.com/getsops/sops/v3/logging" + "github.com/sirupsen/logrus" ) const ( @@ -124,7 +124,7 @@ func (key *MasterKey) Encrypt(dataKey []byte) error { if key.parsedRecipient == nil { parsedRecipient, err := parseRecipient(key.Recipient) if err != nil { - log.WithField("recipient", key.parsedRecipient).Error("Encryption failed") + log.WithField("recipient", key.parsedRecipient).Info("Encryption failed") return err } key.parsedRecipient = parsedRecipient @@ -134,19 +134,19 @@ func (key *MasterKey) Encrypt(dataKey []byte) error { aw := armor.NewWriter(&buffer) w, err := age.Encrypt(aw, key.parsedRecipient) if err != nil { - log.WithField("recipient", key.parsedRecipient).Error("Encryption failed") + log.WithField("recipient", key.parsedRecipient).Info("Encryption failed") return fmt.Errorf("failed to create writer for encrypting sops data key with age: %w", err) } if _, err := w.Write(dataKey); err != nil { - log.WithField("recipient", key.parsedRecipient).Error("Encryption failed") + log.WithField("recipient", key.parsedRecipient).Info("Encryption failed") return fmt.Errorf("failed to encrypt sops data key with age: %w", err) } if err := w.Close(); err != nil { - log.WithField("recipient", key.parsedRecipient).Error("Encryption failed") + log.WithField("recipient", key.parsedRecipient).Info("Encryption failed") return fmt.Errorf("failed to close writer for encrypting sops data key with age: %w", err) } if err := aw.Close(); err != nil { - log.WithField("recipient", key.parsedRecipient).Error("Encryption failed") + log.WithField("recipient", key.parsedRecipient).Info("Encryption failed") return fmt.Errorf("failed to close armored writer: %w", err) } @@ -180,7 +180,7 @@ func (key *MasterKey) Decrypt() ([]byte, error) { if len(key.parsedIdentities) == 0 { ids, err := key.loadIdentities() if err != nil { - log.Error("Decryption failed") + log.Info("Decryption failed") return nil, fmt.Errorf("failed to load age identities: %w", err) } ids.ApplyToMasterKey(key) @@ -190,13 +190,13 @@ func (key *MasterKey) Decrypt() ([]byte, error) { ar := armor.NewReader(src) r, err := age.Decrypt(ar, key.parsedIdentities...) if err != nil { - log.Error("Decryption failed") + log.Info("Decryption failed") return nil, fmt.Errorf("failed to create reader for decrypting sops data key with age: %w", err) } var b bytes.Buffer if _, err := io.Copy(&b, r); err != nil { - log.Error("Decryption failed") + log.Info("Decryption failed") return nil, fmt.Errorf("failed to copy age decrypted data into bytes.Buffer: %w", err) } diff --git a/azkv/keysource.go b/azkv/keysource.go index 6222adc4e7..0646ac5615 100644 --- a/azkv/keysource.go +++ b/azkv/keysource.go @@ -117,13 +117,13 @@ func (t TokenCredential) ApplyToMasterKey(key *MasterKey) { func (key *MasterKey) Encrypt(dataKey []byte) error { token, err := key.getTokenCredential() if err != nil { - log.WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Error("Encryption failed") + log.WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Info("Encryption failed") return fmt.Errorf("failed to get Azure token credential to encrypt data: %w", err) } c, err := azkeys.NewClient(key.VaultURL, token, nil) if err != nil { - log.WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Error("Encryption failed") + log.WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Info("Encryption failed") return fmt.Errorf("failed to construct Azure Key Vault client to encrypt data: %w", err) } @@ -132,7 +132,7 @@ func (key *MasterKey) Encrypt(dataKey []byte) error { Value: dataKey, }, nil) if err != nil { - log.WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Error("Encryption failed") + log.WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Info("Encryption failed") return fmt.Errorf("failed to encrypt sops data key with Azure Key Vault key '%s': %w", key.ToString(), err) } @@ -166,19 +166,19 @@ func (key *MasterKey) EncryptIfNeeded(dataKey []byte) error { func (key *MasterKey) Decrypt() ([]byte, error) { token, err := key.getTokenCredential() if err != nil { - log.WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Error("Decryption failed") + log.WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Info("Decryption failed") return nil, fmt.Errorf("failed to get Azure token credential to decrypt: %w", err) } rawEncryptedKey, err := base64.RawURLEncoding.DecodeString(key.EncryptedKey) if err != nil { - log.WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Error("Decryption failed") + log.WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Info("Decryption failed") return nil, fmt.Errorf("failed to base64 decode Azure Key Vault encrypted key: %w", err) } c, err := azkeys.NewClient(key.VaultURL, token, nil) if err != nil { - log.WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Error("Decryption failed") + log.WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Info("Decryption failed") return nil, fmt.Errorf("failed to construct Azure Key Vault client to decrypt data: %w", err) } @@ -187,7 +187,7 @@ func (key *MasterKey) Decrypt() ([]byte, error) { Value: rawEncryptedKey, }, nil) if err != nil { - log.WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Error("Decryption failed") + log.WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Info("Decryption failed") return nil, fmt.Errorf("failed to decrypt sops data key with Azure Key Vault key '%s': %w", key.ToString(), err) } log.WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Info("Decryption succeeded") diff --git a/gcpkms/keysource.go b/gcpkms/keysource.go index b4ebbff3ea..3ef97b4458 100644 --- a/gcpkms/keysource.go +++ b/gcpkms/keysource.go @@ -94,7 +94,7 @@ func (c CredentialJSON) ApplyToMasterKey(key *MasterKey) { func (key *MasterKey) Encrypt(dataKey []byte) error { service, err := key.newKMSClient() if err != nil { - log.WithField("resourceID", key.ResourceID).Error("Encryption failed") + log.WithField("resourceID", key.ResourceID).Info("Encryption failed") return fmt.Errorf("cannot create GCP KMS service: %w", err) } defer func() { @@ -110,7 +110,7 @@ func (key *MasterKey) Encrypt(dataKey []byte) error { ctx := context.Background() resp, err := service.Encrypt(ctx, req) if err != nil { - log.WithField("resourceID", key.ResourceID).Error("Encryption failed") + log.WithField("resourceID", key.ResourceID).Info("Encryption failed") return fmt.Errorf("failed to encrypt sops data key with GCP KMS key: %w", err) } // NB: base64 encoding is for compatibility with SOPS <=3.8.x. @@ -145,7 +145,7 @@ func (key *MasterKey) EncryptIfNeeded(dataKey []byte) error { func (key *MasterKey) Decrypt() ([]byte, error) { service, err := key.newKMSClient() if err != nil { - log.WithField("resourceID", key.ResourceID).Error("Decryption failed") + log.WithField("resourceID", key.ResourceID).Info("Decryption failed") return nil, fmt.Errorf("cannot create GCP KMS service: %w", err) } defer func() { @@ -158,7 +158,7 @@ func (key *MasterKey) Decrypt() ([]byte, error) { // client used to work with base64 encoded strings. decodedCipher, err := base64.StdEncoding.DecodeString(string(key.EncryptedDataKey())) if err != nil { - log.WithField("resourceID", key.ResourceID).Error("Decryption failed") + log.WithField("resourceID", key.ResourceID).Info("Decryption failed") return nil, err } @@ -169,7 +169,7 @@ func (key *MasterKey) Decrypt() ([]byte, error) { ctx := context.Background() resp, err := service.Decrypt(ctx, req) if err != nil { - log.WithField("resourceID", key.ResourceID).Error("Decryption failed") + log.WithField("resourceID", key.ResourceID).Info("Decryption failed") return nil, fmt.Errorf("failed to decrypt sops data key with GCP KMS key: %w", err) } diff --git a/go.mod b/go.mod index 7a2ec03644..fb0bf6aade 100644 --- a/go.mod +++ b/go.mod @@ -37,9 +37,9 @@ require ( golang.org/x/net v0.15.0 golang.org/x/sys v0.12.0 golang.org/x/term v0.12.0 - google.golang.org/api v0.140.0 - google.golang.org/genproto/googleapis/rpc v0.0.0-20230911183012-2d3300fd4832 - google.golang.org/grpc v1.58.0 + google.golang.org/api v0.141.0 + google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb + google.golang.org/grpc v1.58.1 google.golang.org/protobuf v1.31.0 gopkg.in/ini.v1 v1.67.0 gopkg.in/yaml.v3 v3.0.1 diff --git a/go.sum b/go.sum index 691723ad2f..5c92b4553c 100644 --- a/go.sum +++ b/go.sum @@ -425,8 +425,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -google.golang.org/api v0.140.0 h1:CaXNdYOH5oQQI7l6iKTHHiMTdxZca4/02hRg2U8c2hM= -google.golang.org/api v0.140.0/go.mod h1:aGbCiFgtwb2P6badchFbSBUurV6oR5d50Af4iNJtDdI= +google.golang.org/api v0.141.0 h1:Df6vfMgDoIM6ss0m7H4MPwFwY87WNXHfBIda/Bmfl4E= +google.golang.org/api v0.141.0/go.mod h1:iZqLkdPlXKyG0b90eu6KxVSE4D/ccRF2e/doKD2CnQQ= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= @@ -438,15 +438,15 @@ google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ19 google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5 h1:nIgk/EEq3/YlnmVVXVnm14rC2oxgs1o0ong4sD/rd44= google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5/go.mod h1:5DZzOUPCLYL3mNkQ0ms0F3EuUNZ7py1Bqeq6sxzI7/Q= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230911183012-2d3300fd4832 h1:o4LtQxebKIJ4vkzyhtD2rfUNZ20Zf0ik5YVP5E7G7VE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230911183012-2d3300fd4832/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb h1:Isk1sSH7bovx8Rti2wZK0UZF6oraBDK74uoyLEEVFN0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.58.0 h1:32JY8YpPMSR45K+c3o6b8VL73V+rR8k+DeMIr4vRH8o= -google.golang.org/grpc v1.58.0/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/grpc v1.58.1 h1:OL+Vz23DTtrrldqHK49FUOPHyY75rvFqJfXC84NYW58= +google.golang.org/grpc v1.58.1/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/hcvault/keysource.go b/hcvault/keysource.go index d2aba26f1e..128115705a 100644 --- a/hcvault/keysource.go +++ b/hcvault/keysource.go @@ -130,18 +130,18 @@ func (key *MasterKey) Encrypt(dataKey []byte) error { client, err := vaultClient(key.VaultAddress, key.token) if err != nil { - log.WithField("Path", fullPath).Error("Encryption failed") + log.WithField("Path", fullPath).Info("Encryption failed") return err } secret, err := client.Logical().Write(fullPath, encryptPayload(dataKey)) if err != nil { - log.WithField("Path", fullPath).Error("Encryption failed") + log.WithField("Path", fullPath).Info("Encryption failed") return fmt.Errorf("failed to encrypt sops data key to Vault transit backend '%s': %w", fullPath, err) } encryptedKey, err := encryptedKeyFromSecret(secret) if err != nil { - log.WithField("Path", fullPath).Error("Encryption failed") + log.WithField("Path", fullPath).Info("Encryption failed") return fmt.Errorf("failed to encrypt sops data key to Vault transit backend '%s': %w", fullPath, err) } @@ -175,18 +175,18 @@ func (key *MasterKey) Decrypt() ([]byte, error) { client, err := vaultClient(key.VaultAddress, key.token) if err != nil { - log.WithField("Path", fullPath).Error("Decryption failed") + log.WithField("Path", fullPath).Info("Decryption failed") return nil, err } secret, err := client.Logical().Write(fullPath, decryptPayload(key.EncryptedKey)) if err != nil { - log.WithField("Path", fullPath).Error("Decryption failed") + log.WithField("Path", fullPath).Info("Decryption failed") return nil, fmt.Errorf("failed to decrypt sops data key from Vault transit backend '%s': %w", fullPath, err) } dataKey, err := dataKeyFromSecret(secret) if err != nil { - log.WithField("Path", fullPath).Error("Decryption failed") + log.WithField("Path", fullPath).Info("Decryption failed") return nil, fmt.Errorf("failed to decrypt sops data key from Vault transit backend '%s': %w", fullPath, err) } diff --git a/kms/keysource.go b/kms/keysource.go index 47c369b36d..a283980909 100644 --- a/kms/keysource.go +++ b/kms/keysource.go @@ -194,7 +194,7 @@ func (c CredentialsProvider) ApplyToMasterKey(key *MasterKey) { func (key *MasterKey) Encrypt(dataKey []byte) error { cfg, err := key.createKMSConfig() if err != nil { - log.WithField("arn", key.Arn).Error("Encryption failed") + log.WithField("arn", key.Arn).Info("Encryption failed") return err } client := key.createClient(cfg) @@ -205,7 +205,7 @@ func (key *MasterKey) Encrypt(dataKey []byte) error { } out, err := client.Encrypt(context.TODO(), input) if err != nil { - log.WithField("arn", key.Arn).Error("Encryption failed") + log.WithField("arn", key.Arn).Info("Encryption failed") return fmt.Errorf("failed to encrypt sops data key with AWS KMS: %w", err) } key.EncryptedKey = base64.StdEncoding.EncodeToString(out.CiphertextBlob) @@ -237,12 +237,12 @@ func (key *MasterKey) SetEncryptedDataKey(enc []byte) { func (key *MasterKey) Decrypt() ([]byte, error) { k, err := base64.StdEncoding.DecodeString(key.EncryptedKey) if err != nil { - log.WithField("arn", key.Arn).Error("Decryption failed") + log.WithField("arn", key.Arn).Info("Decryption failed") return nil, fmt.Errorf("error base64-decoding encrypted data key: %s", err) } cfg, err := key.createKMSConfig() if err != nil { - log.WithField("arn", key.Arn).Error("Decryption failed") + log.WithField("arn", key.Arn).Info("Decryption failed") return nil, err } client := key.createClient(cfg) @@ -253,7 +253,7 @@ func (key *MasterKey) Decrypt() ([]byte, error) { } decrypted, err := client.Decrypt(context.TODO(), input) if err != nil { - log.WithField("arn", key.Arn).Error("Decryption failed") + log.WithField("arn", key.Arn).Info("Decryption failed") return nil, fmt.Errorf("failed to decrypt sops data key with AWS KMS: %w", err) } log.WithField("arn", key.Arn).Info("Decryption succeeded") diff --git a/pgp/keysource.go b/pgp/keysource.go index 6bbc33d862..b968a30469 100644 --- a/pgp/keysource.go +++ b/pgp/keysource.go @@ -20,9 +20,9 @@ import ( "github.com/ProtonMail/go-crypto/openpgp" "github.com/ProtonMail/go-crypto/openpgp/armor" + gpgagent "github.com/getsops/gopgagent" "github.com/getsops/sops/v3/logging" "github.com/sirupsen/logrus" - gpgagent "github.com/getsops/gopgagent" "golang.org/x/term" ) @@ -73,9 +73,6 @@ type MasterKey struct { // It can be injected by a (local) keyservice.KeyServiceServer using // GnuPGHome.ApplyToMasterKey(). gnuPGHomeDir string - // disableAgent instructs the MasterKey to not use the GnuPG agent during - // decryption operations. - disableAgent bool // disableOpenPGP instructs the MasterKey to skip attempting to open any // pubRing or secRing using OpenPGP. disableOpenPGP bool @@ -201,14 +198,6 @@ func (d GnuPGHome) ApplyToMasterKey(key *MasterKey) { } } -// DisableAgent disables the GnuPG agent for a MasterKey. -type DisableAgent struct{} - -// ApplyToMasterKey configures the provided key to not use the GnuPG agent. -func (d DisableAgent) ApplyToMasterKey(key *MasterKey) { - key.disableAgent = true -} - // DisableOpenPGP disables encrypt and decrypt operations using OpenPGP. type DisableOpenPGP struct{} @@ -268,7 +257,7 @@ func (key *MasterKey) Encrypt(dataKey []byte) error { } errs = append(errs, fmt.Errorf("GnuPG binary error: %w", binaryErr)) - log.WithField("fingerprint", key.Fingerprint).Error("Encryption failed") + log.WithField("fingerprint", key.Fingerprint).Info("Encryption failed") return fmt.Errorf("could not encrypt data key with PGP key: %w", errs) } @@ -329,7 +318,7 @@ func (key *MasterKey) encryptWithGnuPG(dataKey []byte) error { fingerprint, "--no-encrypt-to", } - err, stdout, stderr := gpgExec(key.gnuPGHome(), args, bytes.NewReader(dataKey)) + err, stdout, stderr := gpgExec(key.gnuPGHomeDir, args, bytes.NewReader(dataKey)) if err != nil { return fmt.Errorf("failed to encrypt sops data key with pgp: %s", strings.TrimSpace(stderr.String())) } @@ -379,7 +368,7 @@ func (key *MasterKey) Decrypt() ([]byte, error) { } errs = append(errs, fmt.Errorf("GnuPG binary error: %w", binaryErr)) - log.WithField("fingerprint", key.Fingerprint).Error("Decryption failed") + log.WithField("fingerprint", key.Fingerprint).Info("Decryption failed") return nil, fmt.Errorf("could not decrypt data key with PGP key: %w", errs) } @@ -418,10 +407,7 @@ func (key *MasterKey) decryptWithGnuPG() ([]byte, error) { args := []string{ "-d", } - if !key.disableAgent { - args = append([]string{"--use-agent"}, args...) - } - err, stdout, stderr := gpgExec(key.gnuPGHome(), args, strings.NewReader(key.EncryptedKey)) + err, stdout, stderr := gpgExec(key.gnuPGHomeDir, args, strings.NewReader(key.EncryptedKey)) if err != nil { return nil, fmt.Errorf("failed to decrypt sops data key with pgp: %s", strings.TrimSpace(stderr.String())) @@ -450,27 +436,6 @@ func (key MasterKey) ToMap() map[string]interface{} { return out } -// gnuPGHome determines the GnuPG home directory for the MasterKey, and returns -// its path. In order of preference: -// 1. MasterKey.gnuPGHomeDir -// 2. $GNUPGHOME -// 3. user.Current().HomeDir/.gnupg -// 4. $HOME/.gnupg -func (key *MasterKey) gnuPGHome() string { - if key.gnuPGHomeDir == "" { - dir := os.Getenv("GNUPGHOME") - if dir == "" { - usr, err := user.Current() - if err != nil { - return filepath.Join(os.Getenv("HOME"), ".gnupg") - } - return filepath.Join(usr.HomeDir, ".gnupg") - } - return dir - } - return key.gnuPGHomeDir -} - // retrievePubKey attempts to retrieve the public key from the public keyring // by Fingerprint. func (key *MasterKey) retrievePubKey() (openpgp.Entity, error) { @@ -493,7 +458,7 @@ func (key *MasterKey) retrievePubKey() (openpgp.Entity, error) { func (key *MasterKey) getPubRing() (openpgp.EntityList, error) { path := key.pubRing if path == "" { - path = filepath.Join(key.gnuPGHome(), defaultPubRing) + path = filepath.Join(gnuPGHome(key.gnuPGHomeDir), defaultPubRing) } return loadRing(path) } @@ -504,7 +469,7 @@ func (key *MasterKey) getPubRing() (openpgp.EntityList, error) { func (key *MasterKey) getSecRing() (openpgp.EntityList, error) { path := key.secRing if path == "" { - path = filepath.Join(key.gnuPGHome(), defaultSecRing) + path = filepath.Join(gnuPGHome(key.gnuPGHomeDir), defaultSecRing) } if _, err := os.Lstat(path); err != nil { if !os.IsNotExist(err) { @@ -597,11 +562,11 @@ func fingerprintIndex(ring openpgp.EntityList) map[string]openpgp.Entity { } // gpgExec runs the provided args with the gpgBinary, while restricting it to -// gnuPGHome. Stdout and stderr can be read from the returned buffers. -// When the command fails, an error is returned. -func gpgExec(gnuPGHome string, args []string, stdin io.Reader) (err error, stdout bytes.Buffer, stderr bytes.Buffer) { - if gnuPGHome != "" { - args = append([]string{"--no-default-keyring", "--homedir", gnuPGHome}, args...) +// homeDir when provided. Stdout and stderr can be read from the returned +// buffers. When the command fails, an error is returned. +func gpgExec(homeDir string, args []string, stdin io.Reader) (err error, stdout bytes.Buffer, stderr bytes.Buffer) { + if homeDir != "" { + args = append([]string{"--homedir", homeDir}, args...) } cmd := exec.Command(gpgBinary(), args...) @@ -623,6 +588,28 @@ func gpgBinary() string { return binary } +// gnuPGHome determines the GnuPG home directory, and returns its path. +// In order of preference: +// 1. customPath +// 2. $GNUPGHOME +// 3. user.Current().HomeDir/.gnupg +// 4. $HOME/.gnupg +func gnuPGHome(customPath string) string { + if customPath != "" { + return customPath + } + + dir := os.Getenv("GNUPGHOME") + if dir == "" { + usr, err := user.Current() + if err != nil { + return filepath.Join(os.Getenv("HOME"), ".gnupg") + } + return filepath.Join(usr.HomeDir, ".gnupg") + } + return dir +} + // shortenFingerprint returns the short ID of the given fingerprint. // This is mostly used for compatability reasons, as older versions of GnuPG // do not always like long IDs. diff --git a/pgp/keysource_test.go b/pgp/keysource_test.go index 1c7c436b46..187a75b1dd 100644 --- a/pgp/keysource_test.go +++ b/pgp/keysource_test.go @@ -148,12 +148,6 @@ func TestGnuPGHome_ApplyToMasterKey(t *testing.T) { assert.NotEqual(t, gnuPGHome.String(), key.gnuPGHomeDir) } -func TestDisableAgent_ApplyToMasterKey(t *testing.T) { - key := NewMasterKeyFromFingerprint(mockFingerprint) - DisableAgent{}.ApplyToMasterKey(key) - assert.True(t, key.disableAgent) -} - func TestDisableOpenPGP_ApplyToMasterKey(t *testing.T) { key := NewMasterKeyFromFingerprint(mockFingerprint) DisableOpenPGP{}.ApplyToMasterKey(key) @@ -277,7 +271,7 @@ func TestMasterKey_encryptWithGnuPG(t *testing.T) { args := []string{ "-d", } - err, stdout, stderr := gpgExec(key.gnuPGHome(), args, strings.NewReader(key.EncryptedKey)) + err, stdout, stderr := gpgExec(key.gnuPGHomeDir, args, strings.NewReader(key.EncryptedKey)) assert.NoError(t, err, stderr.String()) assert.Equal(t, data, stdout.Bytes()) }) @@ -535,24 +529,6 @@ func TestMasterKey_ToMap(t *testing.T) { }, key.ToMap()) } -func TestMasterKey_gnuPGHome(t *testing.T) { - key := &MasterKey{} - - usr, err := user.Current() - if err == nil { - assert.Equal(t, filepath.Join(usr.HomeDir, ".gnupg"), key.gnuPGHome()) - } else { - assert.Equal(t, filepath.Join(os.Getenv("HOME"), ".gnupg"), key.gnuPGHome()) - } - - gnupgHome := "/overwrite/home" - t.Setenv("GNUPGHOME", gnupgHome) - assert.Equal(t, gnupgHome, key.gnuPGHome()) - - key.gnuPGHomeDir = "/home/dir/overwrite" - assert.Equal(t, key.gnuPGHomeDir, key.gnuPGHome()) -} - func TestMasterKey_retrievePubKey(t *testing.T) { t.Run("existing fingerprint", func(t *testing.T) { key := NewMasterKeyFromFingerprint(mockFingerprint) @@ -677,6 +653,22 @@ func Test_gpgBinary(t *testing.T) { assert.Equal(t, overwrite, gpgBinary()) } +func Test_gnuPGHome(t *testing.T) { + usr, err := user.Current() + if err == nil { + assert.Equal(t, filepath.Join(usr.HomeDir, ".gnupg"), gnuPGHome("")) + } else { + assert.Equal(t, filepath.Join(os.Getenv("HOME"), ".gnupg"), gnuPGHome("")) + } + + gnupgHome := "/overwrite/home" + t.Setenv("GNUPGHOME", gnupgHome) + assert.Equal(t, gnupgHome, gnuPGHome("")) + + customP := "/home/dir/overwrite" + assert.Equal(t, customP, gnuPGHome(customP)) +} + func Test_shortenFingerprint(t *testing.T) { shortId := shortenFingerprint(mockFingerprint) assert.Equal(t, "9732075EA221A7EA", shortId) diff --git a/version/version.go b/version/version.go index 006a161520..161bdcdea8 100644 --- a/version/version.go +++ b/version/version.go @@ -12,7 +12,7 @@ import ( ) // Version represents the value of the current semantic version. -var Version = "3.7.3" +var Version = "3.8.0" // PrintVersion prints the current version of sops. If the flag // `--disable-version-check` is set, the function will not attempt