Refuse an exclude pattern that does not compile when the config loads (closes #455)
check / check (push) Canceled after 0s

An exclude pattern that did not compile was skipped with a log warning during the backup, which then stored what it meant to leave out. Config.Validate now refuses such a pattern, global or per snapshot, naming the setting and quoting the pattern. The compile step moves to a new package, internal/exclude, which both the config and the scanner call.

Model: opus-5-5
This commit was merged in pull request #456.
This commit is contained in:
clawbot committed 2026-11-11 10:58:54 +01:00
1 parent 6a8bb2f389
commit 5ca0d46932
6 files changed
+294 -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