|
|
|
@ -18,6 +18,10 @@ package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"regexp/syntax"
|
|
|
|
|
"strings"
|
|
|
|
|
"unicode"
|
|
|
|
|
"unicode/utf8"
|
|
|
|
|
|
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
@ -94,6 +98,8 @@ func createImagePolicyRun(cmd *cobra.Command, args []string) error {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch {
|
|
|
|
|
case imagePolicyArgs.semver != "" && imagePolicyArgs.alpha != "":
|
|
|
|
|
return fmt.Errorf("policy cannot be specified with both --select-semver and --select-alpha")
|
|
|
|
|
case imagePolicyArgs.semver != "":
|
|
|
|
|
policy.Spec.Policy.SemVer = &imagev1.SemVerPolicy{
|
|
|
|
|
Range: imagePolicyArgs.semver,
|
|
|
|
@ -110,11 +116,18 @@ func createImagePolicyRun(cmd *cobra.Command, args []string) error {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if imagePolicyArgs.filterRegex != "" {
|
|
|
|
|
exp, err := syntax.Parse(imagePolicyArgs.filterRegex, syntax.Perl)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("--filter-regex is an invalid regex pattern")
|
|
|
|
|
}
|
|
|
|
|
policy.Spec.FilterTags = &imagev1.TagFilter{
|
|
|
|
|
Pattern: imagePolicyArgs.filterRegex,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if imagePolicyArgs.filterExtract != "" {
|
|
|
|
|
if err := validateExtractStr(imagePolicyArgs.filterExtract, exp.CapNames()); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
policy.Spec.FilterTags.Extract = imagePolicyArgs.filterExtract
|
|
|
|
|
}
|
|
|
|
|
} else if imagePolicyArgs.filterExtract != "" {
|
|
|
|
@ -134,3 +147,94 @@ func createImagePolicyRun(cmd *cobra.Command, args []string) error {
|
|
|
|
|
})
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Performs a dry-run of the extract function in Regexp to validate the template
|
|
|
|
|
func validateExtractStr(template string, capNames []string) error {
|
|
|
|
|
for len(template) > 0 {
|
|
|
|
|
i := strings.Index(template, "$")
|
|
|
|
|
if i < 0 {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
template = template[i:]
|
|
|
|
|
if len(template) > 1 && template[1] == '$' {
|
|
|
|
|
template = template[2:]
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
name, num, rest, ok := extract(template)
|
|
|
|
|
if !ok {
|
|
|
|
|
// Malformed extract string, assume user didn't want this
|
|
|
|
|
template = template[1:]
|
|
|
|
|
return fmt.Errorf("--filter-extract is malformed")
|
|
|
|
|
}
|
|
|
|
|
template = rest
|
|
|
|
|
if num >= 0 {
|
|
|
|
|
// we won't worry about numbers as we can't validate these
|
|
|
|
|
continue
|
|
|
|
|
} else {
|
|
|
|
|
found := false
|
|
|
|
|
for _, capName := range capNames {
|
|
|
|
|
if name == capName {
|
|
|
|
|
found = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if !found {
|
|
|
|
|
return fmt.Errorf("capture group $%s used in --filter-extract not found in --filter-regex", name)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// extract method from the regexp package
|
|
|
|
|
// returns the name or number of the value prepended by $
|
|
|
|
|
func extract(str string) (name string, num int, rest string, ok bool) {
|
|
|
|
|
if len(str) < 2 || str[0] != '$' {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
brace := false
|
|
|
|
|
if str[1] == '{' {
|
|
|
|
|
brace = true
|
|
|
|
|
str = str[2:]
|
|
|
|
|
} else {
|
|
|
|
|
str = str[1:]
|
|
|
|
|
}
|
|
|
|
|
i := 0
|
|
|
|
|
for i < len(str) {
|
|
|
|
|
rune, size := utf8.DecodeRuneInString(str[i:])
|
|
|
|
|
if !unicode.IsLetter(rune) && !unicode.IsDigit(rune) && rune != '_' {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
i += size
|
|
|
|
|
}
|
|
|
|
|
if i == 0 {
|
|
|
|
|
// empty name is not okay
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
name = str[:i]
|
|
|
|
|
if brace {
|
|
|
|
|
if i >= len(str) || str[i] != '}' {
|
|
|
|
|
// missing closing brace
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
i++
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Parse number.
|
|
|
|
|
num = 0
|
|
|
|
|
for i := 0; i < len(name); i++ {
|
|
|
|
|
if name[i] < '0' || '9' < name[i] || num >= 1e8 {
|
|
|
|
|
num = -1
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
num = num*10 + int(name[i]) - '0'
|
|
|
|
|
}
|
|
|
|
|
// Disallow leading zeros.
|
|
|
|
|
if name[0] == '0' && len(name) > 1 {
|
|
|
|
|
num = -1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rest = str[i:]
|
|
|
|
|
ok = true
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|