Skip to content

Commit

Permalink
Merge pull request #49 from slok/slok/regex
Browse files Browse the repository at this point in the history
  • Loading branch information
slok authored Mar 12, 2021
2 parents 199b100 + 2a12166 commit 9c507a6
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 3 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

## Unreleased

### Added

- `--filter` (`-f`) regex to include the matching secrets in `encrypt` cmd.
- `--filter` (`-f`) regex to include the matching secrets in `decrypt` cmd.
- `--filter` (`-f`) regex to include the matching secrets in `untrack` cmd.

## [v0.1.1] - 2021-03-11

### Added
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,24 @@ Encrypt (and track) a directory in dry-run to see what would be encrypted before
agebox encrypt ./secrets --dry-run
```

Encrypt (and track) a directory and only (filter regex used) the `secret` named yaml files.

```bash
agebox encrypt ./manifests --filter ".*secret(\.yaml|\.yml)$"
```

Decrypt a subset of tracked secrets and a file.

```bash
agebox decrypt ./secrets/team-1 ./secrets/secret1.yaml
```

Decrypt only (filter regex used) `team-a` tracked files.

```bash
agebox decrypt ./secrets --filter ".*team-a.*"
```

Validate all tracked encrypted files exist and decryption is possible.

```bash
Expand Down
4 changes: 4 additions & 0 deletions cmd/agebox/commands/decrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"os"
"regexp"

"gopkg.in/alecthomas/kingpin.v2"

Expand All @@ -22,6 +23,7 @@ type decryptCommand struct {
DecryptAll bool
Force bool
DryRun bool
RegexFilter *regexp.Regexp
}

// NewDecryptCommand returns the decrypt command.
Expand All @@ -32,6 +34,7 @@ func NewDecryptCommand(app *kingpin.Application) Command {
cmd.Flag("all", "Decrypts all tracked files.").Short('a').BoolVar(&c.DecryptAll)
cmd.Flag("dry-run", "Enables dry run mode, write operations will be ignored").BoolVar(&c.DryRun)
cmd.Flag("force", "Forces the decryption even if decrypted file exists").BoolVar(&c.Force)
cmd.Flag("filter", "Decrypts only the filenames (without encrypted extension) that match the provided regex").Short('f').RegexpVar(&c.RegexFilter)
cmd.Arg("files", "Files to decrypt.").StringsVar(&c.Files)

return c
Expand Down Expand Up @@ -79,6 +82,7 @@ func (d decryptCommand) Run(ctx context.Context, config RootConfig) error {
secretIDProc := process.NewIDProcessorChain(
process.NewPathSanitizer(""),
process.NewIgnoreAlreadyProcessed(map[string]struct{}{}), // This should be after pathSanitizer.
process.NewIncludeRegexMatch(d.RegexFilter, logger),
process.NewDecryptionPathState(d.Force, secretRepo, logger),
)

Expand Down
4 changes: 4 additions & 0 deletions cmd/agebox/commands/encrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"os"
"regexp"

"gopkg.in/alecthomas/kingpin.v2"

Expand All @@ -21,6 +22,7 @@ type encryptCommand struct {
Files []string
EncryptAll bool
DryRun bool
RegexFilter *regexp.Regexp
}

// NewEncryptCommand returns the encrypt command.
Expand All @@ -30,6 +32,7 @@ func NewEncryptCommand(app *kingpin.Application) Command {
cmd.Flag("public-keys", "Path to public keys.").Default("keys").Short('p').StringVar(&c.PubKeysPath)
cmd.Flag("all", "Encrypts all tracked files.").Short('a').BoolVar(&c.EncryptAll)
cmd.Flag("dry-run", "Enables dry run mode, write operations will be ignored").BoolVar(&c.DryRun)
cmd.Flag("filter", "Encrypts only the filenames (without encrypted extension) that match the provided regex").Short('f').RegexpVar(&c.RegexFilter)
cmd.Arg("files", "Files to encrypt.").StringsVar(&c.Files)

return c
Expand Down Expand Up @@ -85,6 +88,7 @@ func (e encryptCommand) Run(ctx context.Context, config RootConfig) error {
secretIDProc := process.NewIDProcessorChain(
process.NewPathSanitizer(""),
process.NewIgnoreAlreadyProcessed(map[string]struct{}{}), // This should be after pathSanitizer.
process.NewIncludeRegexMatch(e.RegexFilter, logger),
process.NewEncryptionPathState(secretRepo, logger),
)

Expand Down
10 changes: 7 additions & 3 deletions cmd/agebox/commands/untrack.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"os"
"regexp"

"gopkg.in/alecthomas/kingpin.v2"

Expand All @@ -15,9 +16,10 @@ import (
)

type untrackCommand struct {
Files []string
Delete bool
DryRun bool
Files []string
Delete bool
DryRun bool
RegexFilter *regexp.Regexp
}

// NewUntrackCommand returns the untrack command.
Expand All @@ -27,6 +29,7 @@ func NewUntrackCommand(app *kingpin.Application) Command {
cmd.Alias("rm")
cmd.Flag("dry-run", "Enables dry run mode, write operations will be ignored").BoolVar(&c.DryRun)
cmd.Flag("delete", "Deletes the untracked files, encrypted or decrypted").BoolVar(&c.Delete)
cmd.Flag("filter", "Untracks only the filenames (without encrypted extension) that match the provided regex").Short('f').RegexpVar(&c.RegexFilter)
cmd.Arg("files", "Files to decrypt.").StringsVar(&c.Files)

return c
Expand Down Expand Up @@ -71,6 +74,7 @@ func (u untrackCommand) Run(ctx context.Context, config RootConfig) error {
secretIDProc := process.NewIDProcessorChain(
process.NewPathSanitizer(""),
process.NewIgnoreAlreadyProcessed(map[string]struct{}{}), // This should be after pathSanitizer.
process.NewIncludeRegexMatch(u.RegexFilter, logger),
process.NewTrackedState(tracked.EncryptedSecrets, true, logger),
)

Expand Down
21 changes: 21 additions & 0 deletions internal/secret/process/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package process
import (
"context"
"fmt"
"regexp"
"sync"

"github.com/slok/agebox/internal/log"
Expand Down Expand Up @@ -100,3 +101,23 @@ func NewTrackedState(trackedSecretIDs map[string]struct{}, ignoreMissing bool, l
return "", fmt.Errorf("%q secret untracked", secretID)
})
}

// NewIncludeRegexMatch will ignore all the secrets that don't match the provided regex.
// If the regex is nil it will match all (Noop).
func NewIncludeRegexMatch(regex *regexp.Regexp, logger log.Logger) IDProcessor {
// Match all.
if regex == nil {
return NoopIDProcessor
}

return IDProcessorFunc(func(ctx context.Context, secretID string) (string, error) {
logger := logger.WithValues(log.Kv{"secret-id": secretID})

if regex.MatchString(secretID) {
return secretID, nil
}

logger.Debugf("secret ignored by regex unmatch")
return "", nil
})
}
48 changes: 48 additions & 0 deletions internal/secret/process/process_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package process_test
import (
"context"
"fmt"
"regexp"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -192,3 +193,50 @@ func TestTrackedState(t *testing.T) {
})
}
}

func TestIncludeRegexMatch(t *testing.T) {
tests := map[string]struct {
regex *regexp.Regexp
secret string
expSecret string
expErr bool
}{
"A nil regex should match everything.": {
secret: "test1",
expSecret: "test1",
},

"A matching secret should be allowed (all).": {
regex: regexp.MustCompile(".*"),
secret: "test1",
expSecret: "test1",
},

"A matching secret should be allowed.": {
regex: regexp.MustCompile("^test[0-9]$"),
secret: "test2",
expSecret: "test2",
},

"A not matching secret should be ignored.": {
regex: regexp.MustCompile("^notest[0-9]$"),
secret: "test1",
expSecret: "",
},
}

for name, test := range tests {
t.Run(name, func(t *testing.T) {
assert := assert.New(t)

p := process.NewIncludeRegexMatch(test.regex, log.Noop)
gotSecret, err := p.ProcessID(context.TODO(), test.secret)

if test.expErr {
assert.Error(err)
} else if assert.NoError(err) {
assert.Equal(test.expSecret, gotSecret)
}
})
}
}

0 comments on commit 9c507a6

Please sign in to comment.