Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add command to encrypt all files if no argument is provided #61

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
66 changes: 50 additions & 16 deletions cmd/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,75 +4,109 @@ package cmd

import (
"fmt"
"os"

"github.com/Ibotta/sopstool/fileutil"
"github.com/Ibotta/sopstool/sopsyaml"
"github.com/spf13/cobra"
)

// addCmd represents the add command
var addCmd = &cobra.Command{
Aliases: []string{"a", "encrypt"},
Use: "add [files ...]",
Short: "add file to the encryption list",
Long: `Add files to the list of files managed by sopstool`,
Args: cobra.MinimumNArgs(1),
Aliases: []string{"a", "e", "add", "encrypt"},
Use: "add [files ...], add",
Short: "add file to the encryption list and encrypt file. No argument encrypts all in sops config.",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey so I'm thinking that the proposed reencrypt is really update.

Add has the semantics of always adding a new entry to the list.

Update can then be a clean 'already exists (added) and update encrypted file from disk'. Then the 'empty args' version of update could be the proposed.

IMO, this feels cleaner than adding a 'force' flag, which incurs all the logic changes below.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update would have:

no-clean for not cleaning up plaintexts
recursive, r, to update recursive from the given path
arg is a list of files, or directories (where all tracked in the directory are updated, if plaintext exists), default .

Long: `Add files to the list of files managed by sopstool and encrypt them. If no argument is provided, encrypt everything provided in sops config`,
RunE: AddCommand,
}

var noEncrypt bool
var noClean bool
var forceOverwrite bool

func init() {
RootCmd.AddCommand(addCmd)

addCmd.Flags().BoolVarP(&noEncrypt, "no-encrypt", "n", false, "Do not encrypt the file after adding")
addCmd.Flags().BoolVar(&noClean, "no-clean", false, "Do not clean up plaintext after encrypting")
addCmd.Flags().BoolVarP(&forceOverwrite, "force", "f", false, "Force overwriting of encrypted files if they already exist")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a couple proposals to consider:

  • all, A which will, if given a list, directory, or empty arg (synonym .), will add any missing files. This is analogous to git add -A
  • ignore, i which will ignore any already added files (adding only new ones)

I'm partial to A, especially with the path arg.

add:

  • recursive, r, to add recursive from the given path

}

// AddCommand the command for the add command
func AddCommand(_ *cobra.Command, args []string) error {
initConfig()

for _, fileArg := range args {
if len(args) == 0 && len(sopsConfig.EncryptedFiles) == 0 {
fmt.Println("No files specified for encryption and no known encrypted files.")
return nil
}

filesToEncrypt := args
if len(args) == 0 {
filesToEncrypt = sopsConfig.EncryptedFiles
}

encryptedCount := 0
for _, fileArg := range filesToEncrypt {
fn := fileutil.NormalizeToPlaintextFile(fileArg)

if fileutil.ListIndexOf(sopsConfig.EncryptedFiles, fn) >= 0 {
fmt.Println("Already exists", fn)
return nil

// Check if plaintext file exists on disk
if _, err := os.Stat(fn); os.IsNotExist(err) {
fmt.Println("Plaintext version of file does not exist:", fn)
continue
}

// add file to list
sopsConfig.EncryptedFiles = append(sopsConfig.EncryptedFiles, fn)
encryptedFilePath := fileutil.NormalizeToSopsFile(fn)

// Check if encrypted file already exists on disk
if _, err := os.Stat(encryptedFilePath); !os.IsNotExist(err) && !forceOverwrite {
fmt.Printf("Encrypted version of file %s already exists on disk. Do you want to overwrite it? [y/N]: ", encryptedFilePath)
var input string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't do interactive inputs anywhere else in sopstool. I'd like to avoid it I think.

fmt.Scanln(&input)
if input == "" || input == "y" || input == "Y" {
// Continue with the overwriting process
} else {
fmt.Println("Skipping:", encryptedFilePath)
continue
}
}

// Check and add the file to the list if not already present
if fileutil.ListIndexOf(sopsConfig.EncryptedFiles, fn) == -1 {
sopsConfig.EncryptedFiles = append(sopsConfig.EncryptedFiles, fn)
fmt.Println("Added file to encryption list:", fn)
} else {
fmt.Println("File", fn, "is already in the encryption list.")
}

//if the file exists, encrypt it
// Encrypt the file
if !noEncrypt {
err := encrypter.EncryptFile(fn)
if err != nil {
return err
}
encryptedCount++
}

if !noClean {
err := encrypter.RemoveFile(fn)
if err != nil {
return err
}
fmt.Println("Cleaned up plaintext for:", fn)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we maybe do some of the extended output in this at a verbose level?

}

err := sourceCodeManager.AddFileToIgnored(fn)
if err != nil {
return err
}
fmt.Println("added file to list:", fn)
}

err := sopsyaml.WriteEncryptFilesToDisk(sopsConfig.Path, sopsConfig.Tree, sopsConfig.EncryptedFiles)
if err != nil {
return err
}

fmt.Println("Files added")
fmt.Printf("%d file(s) encrypted successfully.\n", encryptedCount)

return nil
}
25 changes: 22 additions & 3 deletions cmd/decrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
package cmd

import (
"fmt"
"os"

"github.com/Ibotta/sopstool/fileutil"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -32,13 +35,29 @@ func DecryptCommand(_ *cobra.Command, args []string) error {
return err
}

//decrypt all the files
decryptedCount := 0 // Counter for successfully decrypted files

// Decrypt all the files
for _, f := range filesToDecrypt {
cryptfile := fileutil.NormalizeToSopsFile(f)
if _, err := os.Stat(cryptfile); os.IsNotExist(err) {
fmt.Println("Encrypted version of file does not exist:", f)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a verbose level for this may be good, and maybe should be associated with the allowFail flag.

// If the encrypted file doesn't exist, skip decryption for this file
continue
}

err := encrypter.DecryptFile(f)
if err != nil && !allowFail {
return err
if err != nil {
if !allowFail {
return err
}
} else {
decryptedCount++ // Increment the counter when decryption is successful
}
}

// Print out the total number of decrypted files
fmt.Printf("%d files decrypted successfully.\n", decryptedCount)

return nil
}
2 changes: 2 additions & 0 deletions oswrap/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ func (ew execWrap) RunCommandStdoutToFile(outfileName string, command []string)
if err != nil {
return err
}
defer outfile.Close() // Close the file after cmd completes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in this case we are explicitly running Close() below, because we want it to be in the order of Close, Remove in the case of an error. (defer are otherwise run in LIFO stack order, so the remove would happen before the close)


cmd.Stdout = outfile

err = cmd.Start()
Expand Down