Bump Buildah to v1.33.1

Bump Buildah to v1.33.1 to get a CVE fix for Buildkit.
I thought it was also going to drag in the test fix as
mentioned in #20709, but I'm not seeing that here.

[NO NEW TESTS NEEDED]
Signed-off-by: TomSweeneyRedHat <tsweeney@redhat.com>
This commit is contained in:
TomSweeneyRedHat
2023-11-19 00:49:10 -05:00
parent 149d4f079a
commit ee16546227
12 changed files with 428 additions and 179 deletions

View File

@@ -0,0 +1,171 @@
package parser
import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"regexp"
"strings"
"github.com/pkg/errors"
)
const (
keySyntax = "syntax"
keyEscape = "escape"
)
var validDirectives = map[string]struct{}{
keySyntax: {},
keyEscape: {},
}
type Directive struct {
Name string
Value string
Location []Range
}
// DirectiveParser is a parser for Dockerfile directives that enforces the
// quirks of the directive parser.
type DirectiveParser struct {
line int
regexp *regexp.Regexp
seen map[string]struct{}
done bool
}
func (d *DirectiveParser) setComment(comment string) {
d.regexp = regexp.MustCompile(fmt.Sprintf(`^%s\s*([a-zA-Z][a-zA-Z0-9]*)\s*=\s*(.+?)\s*$`, comment))
}
func (d *DirectiveParser) ParseLine(line []byte) (*Directive, error) {
d.line++
if d.done {
return nil, nil
}
if d.regexp == nil {
d.setComment("#")
}
match := d.regexp.FindSubmatch(line)
if len(match) == 0 {
d.done = true
return nil, nil
}
k := strings.ToLower(string(match[1]))
if _, ok := validDirectives[k]; !ok {
d.done = true
return nil, nil
}
if d.seen == nil {
d.seen = map[string]struct{}{}
}
if _, ok := d.seen[k]; ok {
return nil, errors.Errorf("only one %s parser directive can be used", k)
}
d.seen[k] = struct{}{}
v := string(match[2])
directive := Directive{
Name: k,
Value: v,
Location: []Range{{
Start: Position{Line: d.line},
End: Position{Line: d.line},
}},
}
return &directive, nil
}
func (d *DirectiveParser) ParseAll(data []byte) ([]*Directive, error) {
scanner := bufio.NewScanner(bytes.NewReader(data))
var directives []*Directive
for scanner.Scan() {
if d.done {
break
}
d, err := d.ParseLine(scanner.Bytes())
if err != nil {
return directives, err
}
if d != nil {
directives = append(directives, d)
}
}
return directives, nil
}
// DetectSyntax returns the syntax of provided input.
//
// The traditional dockerfile directives '# syntax = ...' are used by default,
// however, the function will also fallback to c-style directives '// syntax = ...'
// and json-encoded directives '{ "syntax": "..." }'. Finally, starting lines
// with '#!' are treated as shebangs and ignored.
//
// This allows for a flexible range of input formats, and appropriate syntax
// selection.
func DetectSyntax(dt []byte) (string, string, []Range, bool) {
dt, hadShebang, err := discardShebang(dt)
if err != nil {
return "", "", nil, false
}
line := 0
if hadShebang {
line++
}
// use default directive parser, and search for #syntax=
directiveParser := DirectiveParser{line: line}
if syntax, cmdline, loc, ok := detectSyntaxFromParser(dt, directiveParser); ok {
return syntax, cmdline, loc, true
}
// use directive with different comment prefix, and search for //syntax=
directiveParser = DirectiveParser{line: line}
directiveParser.setComment("//")
if syntax, cmdline, loc, ok := detectSyntaxFromParser(dt, directiveParser); ok {
return syntax, cmdline, loc, true
}
// search for possible json directives
var directive struct {
Syntax string `json:"syntax"`
}
if err := json.Unmarshal(dt, &directive); err == nil {
if directive.Syntax != "" {
loc := []Range{{
Start: Position{Line: line},
End: Position{Line: line},
}}
return directive.Syntax, directive.Syntax, loc, true
}
}
return "", "", nil, false
}
func detectSyntaxFromParser(dt []byte, parser DirectiveParser) (string, string, []Range, bool) {
directives, _ := parser.ParseAll(dt)
for _, d := range directives {
// check for syntax directive before erroring out, since the error
// might have occurred *after* the syntax directive
if d.Name == keySyntax {
p, _, _ := strings.Cut(d.Value, " ")
return p, d.Value, d.Location, true
}
}
return "", "", nil, false
}
func discardShebang(dt []byte) ([]byte, bool, error) {
line, rest, _ := bytes.Cut(dt, []byte("\n"))
if bytes.HasPrefix(line, []byte("#!")) {
return rest, true, nil
}
return dt, false, nil
}

View File

@@ -8,7 +8,6 @@ package parser
import (
"encoding/json"
"fmt"
"strings"
"unicode"
"unicode/utf8"
@@ -34,7 +33,6 @@ func parseIgnore(rest string, d *directives) (*Node, map[string]bool, error) {
// statement with sub-statements.
//
// ONBUILD RUN foo bar -> (onbuild (run foo bar))
//
func parseSubCommand(rest string, d *directives) (*Node, map[string]bool, error) {
if rest == "" {
return nil, nil, nil
@@ -154,7 +152,7 @@ func parseNameVal(rest string, key string, d *directives) (*Node, error) {
if !strings.Contains(words[0], "=") {
parts := reWhitespace.Split(rest, 2)
if len(parts) < 2 {
return nil, fmt.Errorf(key + " must have two arguments")
return nil, errors.Errorf("%s must have two arguments", key)
}
return newKeyValueNode(parts[0], parts[1]), nil
}
@@ -163,7 +161,7 @@ func parseNameVal(rest string, key string, d *directives) (*Node, error) {
var prevNode *Node
for _, word := range words {
if !strings.Contains(word, "=") {
return nil, fmt.Errorf("Syntax error - can't find = in %q. Must be of the form: name=value", word)
return nil, errors.Errorf("Syntax error - can't find = in %q. Must be of the form: name=value", word)
}
parts := strings.SplitN(word, "=", 2)
@@ -274,7 +272,7 @@ func parseString(rest string, d *directives) (*Node, map[string]bool, error) {
func parseJSON(rest string, d *directives) (*Node, map[string]bool, error) {
rest = strings.TrimLeftFunc(rest, unicode.IsSpace)
if !strings.HasPrefix(rest, "[") {
return nil, nil, fmt.Errorf(`Error parsing "%s" as a JSON array`, rest)
return nil, nil, errors.Errorf("Error parsing %q as a JSON array", rest)
}
var myJSON []interface{}

View File

@@ -1,4 +1,5 @@
// Package parser implements a parser and parse tree dumper for Dockerfiles.
// The parser package implements a parser that transforms a raw byte-stream
// into a low-level Abstract Syntax Tree.
package parser
import (
@@ -27,7 +28,6 @@ import (
// This data structure is frankly pretty lousy for handling complex languages,
// but lucky for us the Dockerfile isn't very complicated. This structure
// works a little more effectively than a "proper" parse tree for our needs.
//
type Node struct {
Value string // actual content
Next *Node // the next item in the current sexp
@@ -115,7 +115,6 @@ type Heredoc struct {
var (
dispatch map[string]func(string, *directives) (*Node, map[string]bool, error)
reWhitespace = regexp.MustCompile(`[\t\v\f\r ]+`)
reDirectives = regexp.MustCompile(`^#\s*([a-zA-Z][a-zA-Z0-9]*)\s*=\s*(.+?)\s*$`)
reComment = regexp.MustCompile(`^#.*$`)
reHeredoc = regexp.MustCompile(`^(\d*)<<(-?)([^<]*)$`)
reLeadingTabs = regexp.MustCompile(`(?m)^\t+`)
@@ -124,11 +123,6 @@ var (
// DefaultEscapeToken is the default escape token
const DefaultEscapeToken = '\\'
var validDirectives = map[string]struct{}{
"escape": {},
"syntax": {},
}
var (
// Directives allowed to contain heredocs
heredocDirectives = map[string]bool{
@@ -143,13 +137,12 @@ var (
}
)
// directive is the structure used during a build run to hold the state of
// directives is the structure used during a build run to hold the state of
// parsing directives.
type directives struct {
escapeToken rune // Current escape token
lineContinuationRegex *regexp.Regexp // Current line continuation regex
done bool // Whether we are done looking for directives
seen map[string]struct{} // Whether the escape directive has been seen
parser DirectiveParser
escapeToken rune // Current escape token
lineContinuationRegex *regexp.Regexp // Current line continuation regex
}
// setEscapeToken sets the default token for escaping characters and as line-
@@ -178,40 +171,19 @@ func (d *directives) setEscapeToken(s string) error {
// Parser directives must precede any builder instruction or other comments,
// and cannot be repeated.
func (d *directives) possibleParserDirective(line string) error {
if d.done {
return nil
directive, err := d.parser.ParseLine([]byte(line))
if err != nil {
return err
}
match := reDirectives.FindStringSubmatch(line)
if len(match) == 0 {
d.done = true
return nil
if directive != nil && directive.Name == keyEscape {
return d.setEscapeToken(directive.Value)
}
k := strings.ToLower(match[1])
_, ok := validDirectives[k]
if !ok {
d.done = true
return nil
}
if _, ok := d.seen[k]; ok {
return errors.Errorf("only one %s parser directive can be used", k)
}
d.seen[k] = struct{}{}
if k == "escape" {
return d.setEscapeToken(match[2])
}
return nil
}
// newDefaultDirectives returns a new directives structure with the default escapeToken token
func newDefaultDirectives() *directives {
d := &directives{
seen: map[string]struct{}{},
}
d := &directives{}
d.setEscapeToken(string(DefaultEscapeToken))
return d
}
@@ -274,13 +246,15 @@ func newNodeFromLine(line string, d *directives, comments []string) (*Node, erro
}, nil
}
// Result is the result of parsing a Dockerfile
// Result contains the bundled outputs from parsing a Dockerfile.
type Result struct {
AST *Node
EscapeToken rune
Warnings []Warning
}
// Warning contains information to identify and locate a warning generated
// during parsing.
type Warning struct {
Short string
Detail [][]byte
@@ -301,8 +275,8 @@ func (r *Result) PrintWarnings(out io.Writer) {
}
}
// Parse reads lines from a Reader, parses the lines into an AST and returns
// the AST and escape token
// Parse consumes lines from a provided Reader, parses each line into an AST
// and returns the results of doing so.
func Parse(rwc io.Reader) (*Result, error) {
d := newDefaultDirectives()
currentLine := 0
@@ -421,7 +395,7 @@ func Parse(rwc io.Reader) (*Result, error) {
}, withLocation(handleScannerError(scanner.Err()), currentLine, 0)
}
// Extracts a heredoc from a possible heredoc regex match
// heredocFromMatch extracts a heredoc from a possible heredoc regex match.
func heredocFromMatch(match []string) (*Heredoc, error) {
if len(match) == 0 {
return nil, nil
@@ -457,7 +431,7 @@ func heredocFromMatch(match []string) (*Heredoc, error) {
return nil, err
}
if len(wordsRaw) != len(words) {
return nil, fmt.Errorf("internal lexing of heredoc produced inconsistent results: %s", rest)
return nil, errors.Errorf("internal lexing of heredoc produced inconsistent results: %s", rest)
}
word := words[0]
@@ -475,9 +449,14 @@ func heredocFromMatch(match []string) (*Heredoc, error) {
}, nil
}
// ParseHeredoc parses a heredoc word from a target string, returning the
// components from the doc.
func ParseHeredoc(src string) (*Heredoc, error) {
return heredocFromMatch(reHeredoc.FindStringSubmatch(src))
}
// MustParseHeredoc is a variant of ParseHeredoc that discards the error, if
// there was one present.
func MustParseHeredoc(src string) *Heredoc {
heredoc, _ := ParseHeredoc(src)
return heredoc
@@ -503,6 +482,7 @@ func heredocsFromLine(line string) ([]Heredoc, error) {
return docs, nil
}
// ChompHeredocContent chomps leading tabs from the heredoc.
func ChompHeredocContent(src string) string {
return reLeadingTabs.ReplaceAllString(src, "")
}