From 4bd24b829148ff80510e8b1a14cd998f5cafdee6 Mon Sep 17 00:00:00 2001 From: Chris McGehee Date: Tue, 16 Nov 2021 10:28:51 -0800 Subject: [PATCH] Including line number: Dockerfile FROM not pinned (#1258) Co-authored-by: laurentsimon <64505099+laurentsimon@users.noreply.github.com> --- checks/pinned_dependencies.go | 16 ++++++- checks/pinned_dependencies_test.go | 73 ++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 2 deletions(-) diff --git a/checks/pinned_dependencies.go b/checks/pinned_dependencies.go index c724493031c..95acd3f3d1d 100644 --- a/checks/pinned_dependencies.go +++ b/checks/pinned_dependencies.go @@ -391,14 +391,26 @@ func validateDockerfileIsPinned(pathfn string, content []byte, // Not pinned. ret = false - dl.Warn("dependency not pinned by hash %v: '%v'", pathfn, name) + dl.Warn3(&checker.LogMessage{ + Path: pathfn, + Type: checker.FileTypeSource, + Offset: child.StartLine, + Text: fmt.Sprintf("dependency not pinned by hash: '%v'", name), + Snippet: child.Original, + }) // FROM name. case len(valueList) == 1: name := valueList[0] if !regex.Match([]byte(name)) { ret = false - dl.Warn("dependency not pinned by hash %v: '%v'", pathfn, name) + dl.Warn3(&checker.LogMessage{ + Path: pathfn, + Type: checker.FileTypeSource, + Offset: child.StartLine, + Text: fmt.Sprintf("dependency not pinned by hash: '%v'", name), + Snippet: child.Original, + }) } default: diff --git a/checks/pinned_dependencies_test.go b/checks/pinned_dependencies_test.go index cb9d3bf4948..4b6ba47a826 100644 --- a/checks/pinned_dependencies_test.go +++ b/checks/pinned_dependencies_test.go @@ -383,6 +383,79 @@ func TestDockerfilePinning(t *testing.T) { } } +func TestDockerfilePinningFromLineNumber(t *testing.T) { + t.Parallel() + tests := []struct { + name string + filename string + expected []struct { + snippet string + lineNumber int + } + }{ + { + name: "Non-pinned dockerfile as", + filename: "./testdata/Dockerfile-not-pinned-as", + expected: []struct { + snippet string + lineNumber int + }{ + { + snippet: "FROM python:3.7 as build", + lineNumber: 17, + }, + { + snippet: "FROM build", + lineNumber: 23, + }, + { + snippet: "FROM base2", + lineNumber: 29, + }, + }, + }, + { + name: "Non-pinned dockerfile", + filename: "./testdata/Dockerfile-not-pinned", + expected: []struct { + snippet string + lineNumber int + }{ + { + snippet: "FROM python:3.7", + lineNumber: 17, + }, + }, + }, + } + for _, tt := range tests { + tt := tt // Re-initializing variable so it is not changed while executing the closure below + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + content, err := os.ReadFile(tt.filename) + if err != nil { + t.Errorf("cannot read file: %v", err) + } + dl := scut.TestDetailLogger{} + var pinned pinnedResult + _, err = validateDockerfileIsPinned(tt.filename, content, &dl, &pinned) + if err != nil { + t.Errorf("error during validateDockerfileIsPinned: %v", err) + } + for _, expectedLog := range tt.expected { + isExpectedLog := func(logMessage checker.LogMessage, logType checker.DetailType) bool { + return logMessage.Offset == expectedLog.lineNumber && logMessage.Path == tt.filename && + logMessage.Snippet == expectedLog.snippet && logType == checker.DetailWarn && + strings.Contains(logMessage.Text, "dependency not pinned by hash") + } + if !scut.ValidateLogMessage(isExpectedLog, &dl) { + t.Errorf("test failed: log message not present: %+v", tt.expected) + } + } + }) + } +} + func TestDockerfilePinningWihoutHash(t *testing.T) { t.Parallel() tests := []struct {