Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 28 additions & 13 deletions cmd/sops/edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type runEditorUntilOkOpts struct {
TmpFileName string
OriginalHash []byte
InputStore sops.Store
OutputStore common.Store
ShowMasterKeys bool
Tree *sops.Tree
}
Expand Down Expand Up @@ -147,8 +148,12 @@ func editTree(opts editOpts, tree *sops.Tree, dataKey []byte) ([]byte, error) {

// Let the user edit the file
err = runEditorUntilOk(runEditorUntilOkOpts{
InputStore: opts.InputStore, OriginalHash: origHash, TmpFileName: tmpfileName,
ShowMasterKeys: opts.ShowMasterKeys, Tree: tree})
InputStore: opts.InputStore,
OutputStore: opts.OutputStore,
OriginalHash: origHash,
TmpFileName: tmpfileName,
ShowMasterKeys: opts.ShowMasterKeys,
Tree: tree})
if err != nil {
return nil, err
}
Expand All @@ -169,6 +174,12 @@ func editTree(opts editOpts, tree *sops.Tree, dataKey []byte) ([]byte, error) {
return encryptedFile, nil
}

const pressKeyMsg = "Press enter to return to the editor, or Ctrl+C to exit."

func waitForKeyPress() {
bufio.NewReader(os.Stdin).ReadByte()
}

func runEditorUntilOk(opts runEditorUntilOkOpts) error {
for {
err := runEditor(opts.TmpFileName)
Expand All @@ -191,10 +202,8 @@ func runEditorUntilOk(opts runEditorUntilOkOpts) error {
log.WithField(
"error",
err,
).Errorf("Could not load tree, probably due to invalid " +
"syntax. Press a key to return to the editor, or Ctrl+C to " +
"exit.")
bufio.NewReader(os.Stdin).ReadByte()
).Errorf("Could not load tree, probably due to invalid syntax. " + pressKeyMsg)
waitForKeyPress()
continue
}
if opts.ShowMasterKeys {
Expand All @@ -205,14 +214,22 @@ func runEditorUntilOk(opts runEditorUntilOkOpts) error {
log.WithField(
"error",
err,
).Errorf("SOPS metadata is invalid. Press a key to " +
"return to the editor, or Ctrl+C to exit.")
bufio.NewReader(os.Stdin).ReadByte()
).Errorf("SOPS metadata is invalid. " + pressKeyMsg)
waitForKeyPress()
continue
}
// Replace the whole tree, because otherwise newBranches would
// contain the SOPS metadata
opts.Tree = &t
} else {
if userErr, _ := validateFileForEncryption(opts.OutputStore, newBranches); userErr != nil {
log.WithField(
"error",
userErr.UserError(),
).Errorf("Tree not valid for encryption. " + pressKeyMsg)
waitForKeyPress()
continue
}
}
opts.Tree.Branches = newBranches
needVersionUpdated, err := version.AIsNewerThanB(version.Version, opts.Tree.Metadata.Version)
Expand All @@ -223,10 +240,8 @@ func runEditorUntilOk(opts runEditorUntilOkOpts) error {
opts.Tree.Metadata.Version = version.Version
}
if opts.Tree.Metadata.MasterKeyCount() == 0 {
log.Error("No master keys were provided, so sops can't " +
"encrypt the file. Press a key to return to the editor, or " +
"Ctrl+C to exit.")
bufio.NewReader(os.Stdin).ReadByte()
log.Error("No master keys were provided, so sops can't encrypt the file. " + pressKeyMsg)
waitForKeyPress()
continue
}
break
Expand Down
30 changes: 20 additions & 10 deletions cmd/sops/encrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,28 @@ func (err *fileAlreadyEncryptedError) UserError() string {
"encrypt files that already contain such an entry.\n\n" +
"If this is an unencrypted file, rename the '" + stores.SopsMetadataKey + "' entry.\n\n" +
"If this is an encrypted file and you want to edit it, use the " +
"editor mode, for example: `sops my_file.yaml`"
"editor mode, for example: `sops edit my_file.yaml`"
return wordwrap.WrapString(message, 75)
}

func ensureNoMetadata(opts encryptOpts, branch sops.TreeBranch) error {
if opts.OutputStore.HasSopsTopLevelKey(branch) {
return &fileAlreadyEncryptedError{}
type needAtLeastOneDocument struct{}

func (err *needAtLeastOneDocument) Error() string {
return "Empty file"
}

func (err *needAtLeastOneDocument) UserError() string {
return "File cannot be completely empty, it must contain at least one document"
}

func validateFileForEncryption(outputStore sops.Store, branches []sops.TreeBranch) (sops.UserError, int) {
if len(branches) < 1 {
return &needAtLeastOneDocument{}, codes.NeedAtLeastOneDocument
}
if outputStore.HasSopsTopLevelKey(branches[0]) {
return &fileAlreadyEncryptedError{}, codes.FileAlreadyEncrypted
}
return nil
return nil, 0
}

func metadataFromEncryptionConfig(config encryptConfig) sops.Metadata {
Expand Down Expand Up @@ -96,11 +109,8 @@ func encrypt(opts encryptOpts) (encryptedFile []byte, err error) {
if err != nil {
return nil, common.NewExitError(fmt.Sprintf("Error unmarshalling file: %s", err), codes.CouldNotReadInputFile)
}
if len(branches) < 1 {
return nil, common.NewExitError("File cannot be completely empty, it must contain at least one document", codes.NeedAtLeastOneDocument)
}
if err := ensureNoMetadata(opts, branches[0]); err != nil {
return nil, common.NewExitError(err, codes.FileAlreadyEncrypted)
if err, code := validateFileForEncryption(opts.OutputStore, branches); err != nil {
return nil, common.NewExitError(err, code)
}
path, err := filepath.Abs(opts.InputPath)
if err != nil {
Expand Down
4 changes: 4 additions & 0 deletions cmd/sops/set.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ func set(opts setOpts) ([]byte, bool, error) {
var changed bool
tree.Branches[0], changed = tree.Branches[0].Set(opts.TreePath, opts.Value)

if err, code := validateFileForEncryption(opts.OutputStore, tree.Branches); err != nil {
return nil, false, common.NewExitError(err, code)
}

err = common.EncryptTree(common.EncryptTreeOpts{
DataKey: dataKey, Tree: tree, Cipher: opts.Cipher,
})
Expand Down