feat(misconf): normalize CreatedBy for buildah and legacy docker builder (#8953)

Signed-off-by: nikpivkin <nikita.pivkin@smartforce.io>
This commit is contained in:
Nikita Pivkin
2025-06-04 11:31:07 +06:00
committed by GitHub
parent 521be3a178
commit 65e155fdaf
4 changed files with 40 additions and 7 deletions

2
go.mod
View File

@@ -23,7 +23,7 @@ require (
github.com/aquasecurity/table v1.10.0
github.com/aquasecurity/testdocker v0.0.0-20240730042311-4642e94c7fc8
github.com/aquasecurity/tml v0.6.1
github.com/aquasecurity/trivy-checks v1.11.2-0.20250529074512-7afea1b738c4
github.com/aquasecurity/trivy-checks v1.11.3-0.20250604022615-9a7efa7c9169
github.com/aquasecurity/trivy-db v0.0.0-20250529093513-a12dfc204b6e
github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48
github.com/aquasecurity/trivy-kubernetes v0.9.0

4
go.sum
View File

@@ -800,8 +800,8 @@ github.com/aquasecurity/testdocker v0.0.0-20240730042311-4642e94c7fc8 h1:b43UVqY
github.com/aquasecurity/testdocker v0.0.0-20240730042311-4642e94c7fc8/go.mod h1:wXA9k3uuaxY3yu7gxrxZDPo/04FEMJtwyecdAlYrEIo=
github.com/aquasecurity/tml v0.6.1 h1:y2ZlGSfrhnn7t4ZJ/0rotuH+v5Jgv6BDDO5jB6A9gwo=
github.com/aquasecurity/tml v0.6.1/go.mod h1:OnYMWY5lvI9ejU7yH9LCberWaaTBW7hBFsITiIMY2yY=
github.com/aquasecurity/trivy-checks v1.11.2-0.20250529074512-7afea1b738c4 h1:Njp9YEU+4vqmtcb21lWfivrbiLsdYreohmWQX3+KHiU=
github.com/aquasecurity/trivy-checks v1.11.2-0.20250529074512-7afea1b738c4/go.mod h1:nT69xgRcBD4NlHwTBpWMYirpK5/Zpl8M+XDOgmjMn2k=
github.com/aquasecurity/trivy-checks v1.11.3-0.20250604022615-9a7efa7c9169 h1:TckzIxUX7lZaU9f2lNxCN0noYYP8fzmSQf6a4JdV83w=
github.com/aquasecurity/trivy-checks v1.11.3-0.20250604022615-9a7efa7c9169/go.mod h1:nT69xgRcBD4NlHwTBpWMYirpK5/Zpl8M+XDOgmjMn2k=
github.com/aquasecurity/trivy-db v0.0.0-20250529093513-a12dfc204b6e h1:+B/in1DQDGwQbKhW5pWL8XxBgnZKxXhUznylJ2NCyvs=
github.com/aquasecurity/trivy-db v0.0.0-20250529093513-a12dfc204b6e/go.mod h1:4zd4qZcjhNAHASz5I0O7qapv5h5gSJzSEaZXv/IPOGc=
github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48 h1:JVgBIuIYbwG+ekC5lUHUpGJboPYiCcxiz06RCtz8neI=

View File

@@ -4,6 +4,7 @@ import (
"bytes"
"context"
"fmt"
"regexp"
"strings"
v1 "github.com/google/go-containerregistry/pkg/v1"
@@ -87,6 +88,9 @@ func imageConfigToDockerfile(cfg *v1.ConfigFile) []byte {
case strings.HasPrefix(h.CreatedBy, "/bin/sh -c #(nop)"):
// Instruction other than RUN
createdBy = strings.TrimPrefix(h.CreatedBy, "/bin/sh -c #(nop)")
if strings.HasPrefix(createdBy, " COPY") || strings.HasPrefix(createdBy, " ADD") {
createdBy = normalizeCopyCreatedBy(createdBy)
}
case strings.HasPrefix(h.CreatedBy, "/bin/sh -c"):
// RUN instruction
createdBy = buildRunInstruction(createdBy)
@@ -112,6 +116,9 @@ func imageConfigToDockerfile(cfg *v1.ConfigFile) []byte {
}
}
}
// Remove Buildah-specific suffix (currently only `|inherit Labels=false`)
// cf. https://github.com/containers/buildah/blob/5a02e74b5d0f01e4d68ea0dcdbf5f5f444baa68f/imagebuildah/stage_executor.go#L1885
createdBy = strings.TrimSuffix(createdBy, "|inheritLabels=false")
dockerfile.WriteString(strings.TrimSpace(createdBy) + "\n")
}
@@ -150,6 +157,12 @@ func buildHealthcheckInstruction(health *v1.HealthConfig) string {
return fmt.Sprintf("HEALTHCHECK %s%s%s%s%s", interval, timeout, startPeriod, retries, command)
}
var copyInRe = regexp.MustCompile(`\b((?:file|dir):\S+) in `)
func normalizeCopyCreatedBy(input string) string {
return copyInRe.ReplaceAllString(input, `$1 `)
}
func (a *historyAnalyzer) Required(_ types.OS) bool {
return true
}

View File

@@ -73,7 +73,7 @@ func Test_historyAnalyzer_Analyze(t *testing.T) {
},
History: []v1.History{
{
CreatedBy: "/bin/sh -c #(nop) ADD file:e4d600fc4c9c293efe360be7b30ee96579925d1b4634c94332e2ec73f7d8eca1 /",
CreatedBy: "/bin/sh -c #(nop) ADD foo.txt /",
EmptyLayer: false,
},
{
@@ -99,7 +99,7 @@ func Test_historyAnalyzer_Analyze(t *testing.T) {
types.MisconfResult{
Namespace: "builtin.dockerfile.DS005",
Query: "data.builtin.dockerfile.DS005.deny",
Message: "Consider using 'COPY file:e4d600fc4c9c293efe360be7b30ee96579925d1b4634c94332e2ec73f7d8eca1 /' command instead of 'ADD file:e4d600fc4c9c293efe360be7b30ee96579925d1b4634c94332e2ec73f7d8eca1 /'",
Message: "Consider using 'COPY foo.txt /' command instead of 'ADD foo.txt /'",
PolicyMetadata: types.PolicyMetadata{
ID: "DS005",
AVDID: "AVD-DS-0005",
@@ -119,10 +119,10 @@ func Test_historyAnalyzer_Analyze(t *testing.T) {
Lines: []types.Line{
{
Number: 1,
Content: "ADD file:e4d600fc4c9c293efe360be7b30ee96579925d1b4634c94332e2ec73f7d8eca1 /",
Content: "ADD foo.txt /",
IsCause: true,
Truncated: false,
Highlighted: "\x1b[38;5;64mADD\x1b[0m file:e4d600fc4c9c293efe360be7b30ee96579925d1b4634c94332e2ec73f7d8eca1 /",
Highlighted: "\x1b[38;5;64mADD\x1b[0m foo.txt /",
FirstCause: true,
LastCause: true,
},
@@ -428,6 +428,26 @@ func Test_ImageConfigToDockerfile(t *testing.T) {
expected: `ARG TAG=latest
ENV TAG=latest
ENTRYPOINT ["/bin/sh" "-c" "echo test"]
`,
},
{
name: "buildah backend or docker legacy builder (DOCKER_BUILDKIT=0)",
input: &v1.ConfigFile{
History: []v1.History{
{
CreatedBy: "/bin/sh -c #(nop) COPY dir:3a024d8085bc39741a0a094a8e287a00a760975c7c2e6b5dc6c7d3174b7d1ab6 in ./files |inheritLabels=false",
},
{
CreatedBy: "/bin/sh -c #(nop) ADD file:24d346633efc860b5011cefa5c0af73006e74e5dfb3c5c0e9cb0e90a927931e1 in readme |inheritLabels=false",
},
{
CreatedBy: `/bin/sh -c #(nop) ENTRYPOINT ["/bin/sh"]|inheritLabels=false`,
},
},
},
expected: `COPY dir:3a024d8085bc39741a0a094a8e287a00a760975c7c2e6b5dc6c7d3174b7d1ab6 ./files
ADD file:24d346633efc860b5011cefa5c0af73006e74e5dfb3c5c0e9cb0e90a927931e1 readme
ENTRYPOINT ["/bin/sh"]
`,
},
}