Merge pull request #3819 from lbausch/restore-validate-patterns
restore: validate include/exclude patterns
This commit is contained in:
commit
3934480da4
4 changed files with 75 additions and 0 deletions
10
changelog/unreleased/pull-3819
Normal file
10
changelog/unreleased/pull-3819
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
Enhancement: Validate include/exclude patterns before restoring
|
||||||
|
|
||||||
|
Patterns provided to `restic restore` via `--exclude`, `--iexclude`,
|
||||||
|
`--include` and `--iinclude` weren't validated before running the restore.
|
||||||
|
Invalid patterns would result in error messages being printed repeatedly
|
||||||
|
and possibly unwanted files being restored.
|
||||||
|
restic now validates all patterns before running the restore and aborts with
|
||||||
|
a fatal error if an invalid pattern is detected.
|
||||||
|
|
||||||
|
https://github.com/restic/restic/pull/3819
|
|
@ -70,6 +70,28 @@ func runRestore(opts RestoreOptions, gopts GlobalOptions, args []string) error {
|
||||||
hasExcludes := len(opts.Exclude) > 0 || len(opts.InsensitiveExclude) > 0
|
hasExcludes := len(opts.Exclude) > 0 || len(opts.InsensitiveExclude) > 0
|
||||||
hasIncludes := len(opts.Include) > 0 || len(opts.InsensitiveInclude) > 0
|
hasIncludes := len(opts.Include) > 0 || len(opts.InsensitiveInclude) > 0
|
||||||
|
|
||||||
|
// Validate provided patterns
|
||||||
|
if len(opts.Exclude) > 0 {
|
||||||
|
if valid, invalidPatterns := filter.ValidatePatterns(opts.Exclude); !valid {
|
||||||
|
return errors.Fatalf("--exclude: invalid pattern(s) provided:\n%s", strings.Join(invalidPatterns, "\n"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(opts.InsensitiveExclude) > 0 {
|
||||||
|
if valid, invalidPatterns := filter.ValidatePatterns(opts.InsensitiveExclude); !valid {
|
||||||
|
return errors.Fatalf("--iexclude: invalid pattern(s) provided:\n%s", strings.Join(invalidPatterns, "\n"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(opts.Include) > 0 {
|
||||||
|
if valid, invalidPatterns := filter.ValidatePatterns(opts.Include); !valid {
|
||||||
|
return errors.Fatalf("--include: invalid pattern(s) provided:\n%s", strings.Join(invalidPatterns, "\n"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(opts.InsensitiveInclude) > 0 {
|
||||||
|
if valid, invalidPatterns := filter.ValidatePatterns(opts.InsensitiveInclude); !valid {
|
||||||
|
return errors.Fatalf("--iinclude: invalid pattern(s) provided:\n%s", strings.Join(invalidPatterns, "\n"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for i, str := range opts.InsensitiveExclude {
|
for i, str := range opts.InsensitiveExclude {
|
||||||
opts.InsensitiveExclude[i] = strings.ToLower(str)
|
opts.InsensitiveExclude[i] = strings.ToLower(str)
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,3 +67,40 @@ func TestBackupFailsWhenUsingInvalidPatternsFromFile(t *testing.T) {
|
||||||
*[._]log[.-][0-9]
|
*[._]log[.-][0-9]
|
||||||
!*[._]log[.-][0-9]`, err.Error())
|
!*[._]log[.-][0-9]`, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRestoreFailsWhenUsingInvalidPatterns(t *testing.T) {
|
||||||
|
env, cleanup := withTestEnvironment(t)
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
testRunInit(t, env.gopts)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// Test --exclude
|
||||||
|
err = testRunRestoreAssumeFailure(t, "latest", RestoreOptions{Exclude: []string{"*[._]log[.-][0-9]", "!*[._]log[.-][0-9]"}}, env.gopts)
|
||||||
|
|
||||||
|
rtest.Equals(t, `Fatal: --exclude: invalid pattern(s) provided:
|
||||||
|
*[._]log[.-][0-9]
|
||||||
|
!*[._]log[.-][0-9]`, err.Error())
|
||||||
|
|
||||||
|
// Test --iexclude
|
||||||
|
err = testRunRestoreAssumeFailure(t, "latest", RestoreOptions{InsensitiveExclude: []string{"*[._]log[.-][0-9]", "!*[._]log[.-][0-9]"}}, env.gopts)
|
||||||
|
|
||||||
|
rtest.Equals(t, `Fatal: --iexclude: invalid pattern(s) provided:
|
||||||
|
*[._]log[.-][0-9]
|
||||||
|
!*[._]log[.-][0-9]`, err.Error())
|
||||||
|
|
||||||
|
// Test --include
|
||||||
|
err = testRunRestoreAssumeFailure(t, "latest", RestoreOptions{Include: []string{"*[._]log[.-][0-9]", "!*[._]log[.-][0-9]"}}, env.gopts)
|
||||||
|
|
||||||
|
rtest.Equals(t, `Fatal: --include: invalid pattern(s) provided:
|
||||||
|
*[._]log[.-][0-9]
|
||||||
|
!*[._]log[.-][0-9]`, err.Error())
|
||||||
|
|
||||||
|
// Test --iinclude
|
||||||
|
err = testRunRestoreAssumeFailure(t, "latest", RestoreOptions{InsensitiveInclude: []string{"*[._]log[.-][0-9]", "!*[._]log[.-][0-9]"}}, env.gopts)
|
||||||
|
|
||||||
|
rtest.Equals(t, `Fatal: --iinclude: invalid pattern(s) provided:
|
||||||
|
*[._]log[.-][0-9]
|
||||||
|
!*[._]log[.-][0-9]`, err.Error())
|
||||||
|
}
|
||||||
|
|
|
@ -131,6 +131,12 @@ func testRunRestoreIncludes(t testing.TB, gopts GlobalOptions, dir string, snaps
|
||||||
rtest.OK(t, runRestore(opts, gopts, []string{snapshotID.String()}))
|
rtest.OK(t, runRestore(opts, gopts, []string{snapshotID.String()}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testRunRestoreAssumeFailure(t testing.TB, snapshotID string, opts RestoreOptions, gopts GlobalOptions) error {
|
||||||
|
err := runRestore(opts, gopts, []string{snapshotID})
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func testRunCheck(t testing.TB, gopts GlobalOptions) {
|
func testRunCheck(t testing.TB, gopts GlobalOptions) {
|
||||||
opts := CheckOptions{
|
opts := CheckOptions{
|
||||||
ReadData: true,
|
ReadData: true,
|
||||||
|
|
Loading…
Reference in a new issue