fix(misconf): map healthcheck start period flag to --start-period instead of --startPeriod (#9837)

Signed-off-by: nikpivkin <nikita.pivkin@smartforce.io>
This commit is contained in:
Nikita Pivkin
2025-11-26 11:38:14 +06:00
committed by GitHub
parent f5bbb0b91a
commit 7b2b4d4b45
5 changed files with 41 additions and 12 deletions

View File

@@ -155,7 +155,7 @@ func buildHealthcheckInstruction(health *v1.HealthConfig) string {
timeout = fmt.Sprintf("--timeout=%s ", health.Timeout)
}
if health.StartPeriod != 0 {
startPeriod = fmt.Sprintf("--startPeriod=%s ", health.StartPeriod)
startPeriod = fmt.Sprintf("--start-period=%s ", health.StartPeriod)
}
if health.Retries != 0 {
retries = fmt.Sprintf("--retries=%d ", health.Retries)

View File

@@ -6,12 +6,12 @@ import (
"time"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/moby/buildkit/frontend/dockerfile/parser"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
"github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/iac/scanners/dockerfile/parser"
)
func Test_historyAnalyzer_Analyze(t *testing.T) {
@@ -384,7 +384,7 @@ func Test_ImageConfigToDockerfile(t *testing.T) {
},
},
},
expected: "HEALTHCHECK --interval=5m0s --timeout=3s --startPeriod=1s --retries=3 CMD curl -f http://localhost/ || exit 1\n",
expected: "HEALTHCHECK --interval=5m0s --timeout=3s --start-period=1s --retries=3 CMD curl -f http://localhost/ || exit 1\n",
},
{
name: "healthcheck instruction exec arguments directly",
@@ -474,7 +474,8 @@ ENTRYPOINT ["/bin/sh"]
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := imageConfigToDockerfile(tt.input)
_, err := parser.Parse(bytes.NewReader(got))
p := parser.NewParser(parser.WithStrict())
_, err := p.Parse(t.Context(), bytes.NewReader(got), "Dockerfile")
require.NoError(t, err)
assert.Equal(t, tt.expected, string(got))

View File

@@ -13,7 +13,30 @@ import (
"github.com/aquasecurity/trivy/pkg/iac/providers/dockerfile"
)
func Parse(_ context.Context, r io.Reader, path string) ([]*dockerfile.Dockerfile, error) {
type Parser struct {
strict bool
}
type Option func(p *Parser)
// WithStrict returns a Parser option that enables strict parsing mode.
// By default, the Parser runs in non-strict mode, where unknown flags are ignored.
// Calling this option ensures that unknown flags cause an error.
func WithStrict() Option {
return func(p *Parser) {
p.strict = true
}
}
func NewParser(opts ...Option) *Parser {
p := &Parser{}
for _, opt := range opts {
opt(p)
}
return p
}
func (p *Parser) Parse(_ context.Context, r io.Reader, path string) ([]*dockerfile.Dockerfile, error) {
parsed, err := parser.Parse(r)
if err != nil {
return nil, xerrors.Errorf("dockerfile parse error: %w", err)
@@ -29,7 +52,7 @@ func Parse(_ context.Context, r io.Reader, path string) ([]*dockerfile.Dockerfil
for _, child := range parsed.AST.Children {
child.Value = strings.ToLower(child.Value)
instr, err := parseInstruction(child)
instr, err := p.parseInstruction(child)
if err != nil {
return nil, xerrors.Errorf("parse dockerfile instruction: %w", err)
}
@@ -90,11 +113,13 @@ func Parse(_ context.Context, r io.Reader, path string) ([]*dockerfile.Dockerfil
return []*dockerfile.Dockerfile{&parsedFile}, nil
}
func parseInstruction(child *parser.Node) (any, error) {
func (p *Parser) parseInstruction(child *parser.Node) (any, error) {
for {
instr, err := instructions.ParseInstruction(child)
if err == nil {
return instr, nil
} else if p.strict {
return nil, xerrors.Errorf("parse instruction %q: %w", child.Value, err)
}
flagName := extractUnknownFlag(err.Error())

View File

@@ -17,8 +17,8 @@ COPY . /app
RUN make /app
CMD python /app/app.py
`
dfs, err := parser.Parse(t.Context(), strings.NewReader(input), "Dockerfile")
p := parser.NewParser()
dfs, err := p.Parse(t.Context(), strings.NewReader(input), "Dockerfile")
require.NoError(t, err)
require.Len(t, dfs, 1)
@@ -65,7 +65,8 @@ RUN --baz --baz --network=host make /app
ONBUILD RUN --foo make /app
CMD python /app/app.py
`
dfs, err := parser.Parse(t.Context(), strings.NewReader(input), "Dockerfile")
p := parser.NewParser()
dfs, err := p.Parse(t.Context(), strings.NewReader(input), "Dockerfile")
require.NoError(t, err)
require.Len(t, dfs, 1)
@@ -170,7 +171,8 @@ EOF`,
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
dfs, err := parser.Parse(t.Context(), strings.NewReader(tt.src), "Dockerfile")
p := parser.NewParser()
dfs, err := p.Parse(t.Context(), strings.NewReader(tt.src), "Dockerfile")
require.NoError(t, err)
require.Len(t, dfs, 1)

View File

@@ -12,7 +12,8 @@ func NewScanner(opts ...options.ScannerOption) *generic.GenericScanner[*dockerfi
defaultOpts := []options.ScannerOption{
generic.WithSupportsInlineIgnore[*dockerfile.Dockerfile](true),
}
p := generic.ParseFunc[*dockerfile.Dockerfile](parser.Parse)
p := parser.NewParser()
return generic.NewScanner("Dockerfile", types.SourceDockerfile, p, append(defaultOpts, opts...)...,
)
}