This repository has no description
1package models
2
3import (
4 "fmt"
5 "regexp"
6 "strings"
7)
8
9type CacheEntry struct {
10 Key string `yaml:"key"`
11 Hash []string `yaml:"hash"`
12 Paths []string `yaml:"paths"`
13 // 1 is fastest, 19 is smallest, 0 is the zstd default
14 CompressionLevel int `yaml:"compression-level"`
15 // on-success is the default, always also saves on failed runs
16 When string `yaml:"when"`
17}
18
19// keys become storage paths, so no slashes
20var cacheKeyRe = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$`)
21
22func (c CacheEntry) Validate() error {
23 if !cacheKeyRe.MatchString(c.Key) {
24 return fmt.Errorf("cache: invalid key %q (allowed: letters, digits, '.', '_', '-')", c.Key)
25 }
26 for _, f := range c.Hash {
27 // rev-parse needs plain repo-relative paths, not pathspecs
28 if f == "" || strings.HasPrefix(f, "/") || strings.HasPrefix(f, "..") {
29 return fmt.Errorf("cache %q: hash path %q is not repo-relative", c.Key, f)
30 }
31 if strings.ContainsAny(f, ": \t\n\"'`$\\*?[") || strings.Contains(f, "/../") || strings.HasSuffix(f, "/..") {
32 return fmt.Errorf("cache %q: hash path %q contains unsupported characters", c.Key, f)
33 }
34 }
35 if len(c.Paths) == 0 {
36 return fmt.Errorf("cache %q: no paths", c.Key)
37 }
38 if c.CompressionLevel < 0 || c.CompressionLevel > 19 {
39 return fmt.Errorf("cache %q: compression-level %d out of range (1-19)", c.Key, c.CompressionLevel)
40 }
41 switch c.When {
42 case "", "on-success", "always":
43 default:
44 return fmt.Errorf("cache %q: when %q is not one of on-success, always", c.Key, c.When)
45 }
46 seen := make(map[string]bool, len(c.Paths))
47 for _, p := range c.Paths {
48 if p == "" {
49 return fmt.Errorf("cache %q: empty path", c.Key)
50 }
51 if strings.ContainsAny(p, " \t\n\"'`$\\") {
52 return fmt.Errorf("cache %q: path %q contains unsupported characters", c.Key, p)
53 }
54 if strings.Contains(p, "..") {
55 return fmt.Errorf("cache %q: path %q must not contain '..'", c.Key, p)
56 }
57 if seen[p] {
58 return fmt.Errorf("cache %q: duplicate path %q", c.Key, p)
59 }
60 seen[p] = true
61 }
62 return nil
63}