Refuse an exclude pattern that does not compile at config load (closes #455)
check / check (push) Successful in 11m26s

An exclude pattern that did not compile was skipped with a warning during the backup, which then stored what the user meant to leave out. Config.Validate now refuses it, naming the setting and quoting the pattern, for example exclude[2]: "build[" is not a valid exclude pattern: ...

The compile step moves to config.CompileExcludePattern, which Validate and the scanner both call. The scanner's skip-and-warn path is gone; a pattern that does not compile there now fails the scanner.

Model: opus-5-5
This commit is contained in:
clawbot committed 2026-11-11 08:40:47 +00:00
1 parent 6a8bb2f389
commit 5e33284ef5
4 files changed
+212 -69

No files matched your search

+25 -7
View File
@@ -396,6 +396,8 @@ func Parse(data []byte) (*Config, error) {
// never the value. An empty list is accepted, because only snapshot
// create needs a recipient and it checks for one itself
// - At least one snapshot must be configured with at least one path
// - Every exclude pattern, global or in a snapshot, must compile; errors
// name the setting and quote the pattern
// - Storage must be configured (either storage_url or s3.* fields)
// - The index path must be absolute: a relative one would resolve against
// the working directory, so each directory would get its own index
@@ -416,18 +418,18 @@ func (c *Config) Validate() error {
}
}
if len(c.Snapshots) == 0 {
return errNoSnapshots
err := c.validateSnapshots()
if err != nil {
return err
}
for name, snap := range c.Snapshots {
if len(snap.Paths) == 0 {
return fmt.Errorf("%w: %q", errSnapshotNoPaths, name)
}
err = c.validateExcludes()
if err != nil {
return err
}
// Validate storage configuration
err := c.validateStorage()
err = c.validateStorage()
if err != nil {
return err
}
@@ -466,6 +468,22 @@ func (c *Config) Validate() error {
return nil
}
// validateSnapshots refuses a config with no snapshot or with a snapshot
// that has no path.
func (c *Config) validateSnapshots() error {
if len(c.Snapshots) == 0 {
return errNoSnapshots
}
for name, snap := range c.Snapshots {
if len(snap.Paths) == 0 {
return fmt.Errorf("%w: %q", errSnapshotNoPaths, name)
}
}
return nil
}
// validateAgeRecipient parses one age_recipients entry with the age library
// and returns a value-free error on failure. A recipient string can be
// sensitive (an operator may paste a secret key by mistake), so neither the