Skip to content

Commit 0e3c5ec

Browse files
authored
Merge pull request #2098 from felixfontein/metadata
Check for metadata key(s) before re-encrypting file
2 parents b01ba10 + 4419fa1 commit 0e3c5ec

3 files changed

Lines changed: 52 additions & 23 deletions

File tree

cmd/sops/edit.go

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ type runEditorUntilOkOpts struct {
3939
TmpFileName string
4040
OriginalHash []byte
4141
InputStore sops.Store
42+
OutputStore common.Store
4243
ShowMasterKeys bool
4344
Tree *sops.Tree
4445
}
@@ -147,8 +148,12 @@ func editTree(opts editOpts, tree *sops.Tree, dataKey []byte) ([]byte, error) {
147148

148149
// Let the user edit the file
149150
err = runEditorUntilOk(runEditorUntilOkOpts{
150-
InputStore: opts.InputStore, OriginalHash: origHash, TmpFileName: tmpfileName,
151-
ShowMasterKeys: opts.ShowMasterKeys, Tree: tree})
151+
InputStore: opts.InputStore,
152+
OutputStore: opts.OutputStore,
153+
OriginalHash: origHash,
154+
TmpFileName: tmpfileName,
155+
ShowMasterKeys: opts.ShowMasterKeys,
156+
Tree: tree})
152157
if err != nil {
153158
return nil, err
154159
}
@@ -169,6 +174,12 @@ func editTree(opts editOpts, tree *sops.Tree, dataKey []byte) ([]byte, error) {
169174
return encryptedFile, nil
170175
}
171176

177+
const pressKeyMsg = "Press enter to return to the editor, or Ctrl+C to exit."
178+
179+
func waitForKeyPress() {
180+
bufio.NewReader(os.Stdin).ReadByte()
181+
}
182+
172183
func runEditorUntilOk(opts runEditorUntilOkOpts) error {
173184
for {
174185
err := runEditor(opts.TmpFileName)
@@ -191,10 +202,8 @@ func runEditorUntilOk(opts runEditorUntilOkOpts) error {
191202
log.WithField(
192203
"error",
193204
err,
194-
).Errorf("Could not load tree, probably due to invalid " +
195-
"syntax. Press a key to return to the editor, or Ctrl+C to " +
196-
"exit.")
197-
bufio.NewReader(os.Stdin).ReadByte()
205+
).Errorf("Could not load tree, probably due to invalid syntax. " + pressKeyMsg)
206+
waitForKeyPress()
198207
continue
199208
}
200209
if opts.ShowMasterKeys {
@@ -205,14 +214,22 @@ func runEditorUntilOk(opts runEditorUntilOkOpts) error {
205214
log.WithField(
206215
"error",
207216
err,
208-
).Errorf("SOPS metadata is invalid. Press a key to " +
209-
"return to the editor, or Ctrl+C to exit.")
210-
bufio.NewReader(os.Stdin).ReadByte()
217+
).Errorf("SOPS metadata is invalid. " + pressKeyMsg)
218+
waitForKeyPress()
211219
continue
212220
}
213221
// Replace the whole tree, because otherwise newBranches would
214222
// contain the SOPS metadata
215223
opts.Tree = &t
224+
} else {
225+
if userErr, _ := validateFileForEncryption(opts.OutputStore, newBranches); userErr != nil {
226+
log.WithField(
227+
"error",
228+
userErr.UserError(),
229+
).Errorf("Tree not valid for encryption. " + pressKeyMsg)
230+
waitForKeyPress()
231+
continue
232+
}
216233
}
217234
opts.Tree.Branches = newBranches
218235
needVersionUpdated, err := version.AIsNewerThanB(version.Version, opts.Tree.Metadata.Version)
@@ -223,10 +240,8 @@ func runEditorUntilOk(opts runEditorUntilOkOpts) error {
223240
opts.Tree.Metadata.Version = version.Version
224241
}
225242
if opts.Tree.Metadata.MasterKeyCount() == 0 {
226-
log.Error("No master keys were provided, so sops can't " +
227-
"encrypt the file. Press a key to return to the editor, or " +
228-
"Ctrl+C to exit.")
229-
bufio.NewReader(os.Stdin).ReadByte()
243+
log.Error("No master keys were provided, so sops can't encrypt the file. " + pressKeyMsg)
244+
waitForKeyPress()
230245
continue
231246
}
232247
break

cmd/sops/encrypt.go

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,28 @@ func (err *fileAlreadyEncryptedError) UserError() string {
5252
"encrypt files that already contain such an entry.\n\n" +
5353
"If this is an unencrypted file, rename the '" + stores.SopsMetadataKey + "' entry.\n\n" +
5454
"If this is an encrypted file and you want to edit it, use the " +
55-
"editor mode, for example: `sops my_file.yaml`"
55+
"editor mode, for example: `sops edit my_file.yaml`"
5656
return wordwrap.WrapString(message, 75)
5757
}
5858

59-
func ensureNoMetadata(opts encryptOpts, branch sops.TreeBranch) error {
60-
if opts.OutputStore.HasSopsTopLevelKey(branch) {
61-
return &fileAlreadyEncryptedError{}
59+
type needAtLeastOneDocument struct{}
60+
61+
func (err *needAtLeastOneDocument) Error() string {
62+
return "Empty file"
63+
}
64+
65+
func (err *needAtLeastOneDocument) UserError() string {
66+
return "File cannot be completely empty, it must contain at least one document"
67+
}
68+
69+
func validateFileForEncryption(outputStore sops.Store, branches []sops.TreeBranch) (sops.UserError, int) {
70+
if len(branches) < 1 {
71+
return &needAtLeastOneDocument{}, codes.NeedAtLeastOneDocument
72+
}
73+
if outputStore.HasSopsTopLevelKey(branches[0]) {
74+
return &fileAlreadyEncryptedError{}, codes.FileAlreadyEncrypted
6275
}
63-
return nil
76+
return nil, 0
6477
}
6578

6679
func metadataFromEncryptionConfig(config encryptConfig) sops.Metadata {
@@ -96,11 +109,8 @@ func encrypt(opts encryptOpts) (encryptedFile []byte, err error) {
96109
if err != nil {
97110
return nil, common.NewExitError(fmt.Sprintf("Error unmarshalling file: %s", err), codes.CouldNotReadInputFile)
98111
}
99-
if len(branches) < 1 {
100-
return nil, common.NewExitError("File cannot be completely empty, it must contain at least one document", codes.NeedAtLeastOneDocument)
101-
}
102-
if err := ensureNoMetadata(opts, branches[0]); err != nil {
103-
return nil, common.NewExitError(err, codes.FileAlreadyEncrypted)
112+
if err, code := validateFileForEncryption(opts.OutputStore, branches); err != nil {
113+
return nil, common.NewExitError(err, code)
104114
}
105115
path, err := filepath.Abs(opts.InputPath)
106116
if err != nil {

cmd/sops/set.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ func set(opts setOpts) ([]byte, bool, error) {
5151
var changed bool
5252
tree.Branches[0], changed = tree.Branches[0].Set(opts.TreePath, opts.Value)
5353

54+
if err, code := validateFileForEncryption(opts.OutputStore, tree.Branches); err != nil {
55+
return nil, false, common.NewExitError(err, code)
56+
}
57+
5458
err = common.EncryptTree(common.EncryptTreeOpts{
5559
DataKey: dataKey, Tree: tree, Cipher: opts.Cipher,
5660
})

0 commit comments

Comments
 (0)