-
Notifications
You must be signed in to change notification settings - Fork 105
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Vulnerability Scanning Implementation for container images #1489
base: main
Are you sure you want to change the base?
Vulnerability Scanning Implementation for container images #1489
Conversation
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
/kind feature |
c5ea814
to
a8fd62f
Compare
pkg/image/vulnerability_scan.go
Outdated
) | ||
|
||
const ( | ||
VulnerabilityCountLimit = 50 // Number of vulnerabilities to be added to buildrun output. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Would be nice to have it configurable for downstream projects to adapt to their needs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@HeavyWombat Shall I add it as another field for vulnerabilityScanOptions ? or Can I set it as an environment variable in some config or in the image-processing container ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My initial feeling would be an environment variable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be in config.go which reads from environment variables.
eaddddc
to
476489d
Compare
476489d
to
204320b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, thanks for the PR. I am generally speaking fine with it, but have a couple of detail questions.
pkg/image/vulnerability_scan.go
Outdated
) | ||
|
||
const ( | ||
VulnerabilityCountLimit = 50 // Number of vulnerabilities to be added to buildrun output. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My initial feeling would be an environment variable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work.
pkg/image/vulnerability_scan.go
Outdated
) | ||
|
||
const ( | ||
VulnerabilityCountLimit = 50 // Number of vulnerabilities to be added to buildrun output. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be in config.go which reads from environment variables.
pkg/reconciler/buildrun/buildrun.go
Outdated
return reconcile.Result{}, resources.UpdateConditionWithFalseStatus(ctx, r.client, buildRun, fmt.Sprintf("Vulnerabilities have been found in the output image. For detailed information, see kubectl --namespace %s logs %s --container step-image-processing", | ||
buildRun.Namespace, | ||
lastTaskRun.Status.PodName, | ||
), "VulnerabilitiesFound") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the message, should we say "check the BuildRun status, or see kubectl ..." ?
Can we put VulnerabilitiesFound
into a constant ? Would be nearby here:
BuildRunStatePodEvicted = "PodEvicted" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -145,6 +145,12 @@ type GitSourceResult struct { | |||
BranchName string `json:"branchName,omitempty"` | |||
} | |||
|
|||
// Vulnerability defines a vulnerability by its ID and severity | |||
type Vulnerability struct { | |||
VulnerabilityID string `json:"vulnerabilityID,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The section is called vulnerabilities, then no nead to call it vulnerabilityID insight of it.
VulnerabilityID string `json:"vulnerabilityID,omitempty"` | |
ID string `json:"id,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did that because it was easy to map it with the result from Trivy scan. I will create a different struct for trivy result.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
||
// Ensure the BuildRun has been created | ||
err := testBuild.CreateBR(testBuildRun) | ||
Expect(err).ToNot(HaveOccurred(), "Failed to create BuildRun") | ||
if _, err := testBuild.GetBR(testBuildRun.Name); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not understand that check. Why do we need to check if the BuildRun exists ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because in my tests, I have already created the buildrun, otherwise I had to create a new function for running buildruns.
This condition is also present in validateBuildRunToSucceed
function.
03ae3cd
to
fea1096
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, thanks for the PR. I only found some small things we should change, but it looks mostly very good to me already.
test "github.com/shipwright-io/build/test/v1beta1_samples" | ||
) | ||
|
||
var _ = Describe("Integration tests Build and BuildRuns", func() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
var _ = Describe("Integration tests Build and BuildRuns", func() { | |
var _ = Describe("Vulnerability scan tests", func() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since it is in the integration
package, I would say we do not need to repeat that in the name of the tests here.
test/e2e/v1beta1/common_cbs_test.go
Outdated
func (c *clusterBuildStrategyPrototype) TestMe(f func(clusterBuildStrategy *buildv1beta1.ClusterBuildStrategy)) { | ||
cbs, err := c.Create() | ||
Expect(err).ToNot(HaveOccurred()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Assuming the Expect
in this helper function are not causing issues a lot, I would say that it qualifies as a Ginkgo helper function and we should declare it as such.
func (c *clusterBuildStrategyPrototype) TestMe(f func(clusterBuildStrategy *buildv1beta1.ClusterBuildStrategy)) { | |
cbs, err := c.Create() | |
Expect(err).ToNot(HaveOccurred()) | |
func (c *clusterBuildStrategyPrototype) TestMe(f func(clusterBuildStrategy *buildv1beta1.ClusterBuildStrategy)) { | |
GinkgoHelper() | |
cbs, err := c.Create() | |
Expect(err).ToNot(HaveOccurred()) |
test/e2e/v1beta1/common_cbs_test.go
Outdated
|
||
. "github.com/onsi/gomega" | ||
|
||
meta "k8s.io/apimachinery/pkg/apis/meta/v1" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Super)Nit: Can we rename it metav1
? I think this is the more widely used import name.
pkg/validate/output_test.go
Outdated
} | ||
}) | ||
|
||
It("should fail for invvalid severities", func() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It("should fail for invvalid severities", func() { | |
It("should fail for invalid severities", func() { |
}) | ||
|
||
resources.UpdateBuildRunUsingTaskResults(ctx, br, tr.Status.Results, taskRunRequest) | ||
|
||
Expect(br.Status.Output.Digest).To(Equal(imageDigest)) | ||
Expect(br.Status.Output.Size).To(Equal(int64(230))) | ||
Expect(len(br.Status.Output.Vulnerabilities)).To(Equal(2)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I recently learned there is a Ginkgo/Gomega idiomatic way to write that (didn't check the syntax again, but I think it is like this):
Expect(len(br.Status.Output.Vulnerabilities)).To(Equal(2)) | |
Expect(br.Status.Output.Vulnerabilities).To(HaveLen(2)) |
fea1096
to
6ddd690
Compare
6ddd690
to
313ea2d
Compare
cmd/image-processing/main_test.go
Outdated
"--vuln-count-limit", "10", | ||
)).ToNot(HaveOccurred()) | ||
output := filecontent(filename) | ||
Expect(strings.Contains(output, "CVE-2019-8457")).To(BeTrue()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will produce a better output in case substring is not found:
Expect(strings.Contains(output, "CVE-2019-8457")).To(BeTrue()) | |
Expect(output).To(ContainSubstring("CVE-2019-8457")) |
cmd/image-processing/main_test.go
Outdated
"--vuln-settings", vulnSettings.String(), | ||
"--result-file-image-vulnerabilities", filename, | ||
)).ToNot(HaveOccurred()) | ||
Expect(strings.Contains(filecontent(filename), "CVE-2019-8457")).To(BeTrue()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Expect(strings.Contains(filecontent(filename), "CVE-2019-8457")).To(BeTrue()) | |
output := filecontent(filename) | |
Expect(output).To(ContainSubstring("CVE-2019-8457")) |
cmd/image-processing/main_test.go
Outdated
"--vuln-settings", vulnSettings.String(), | ||
"--result-file-image-vulnerabilities", filename, | ||
)).To(HaveOccurred()) | ||
Expect(strings.Contains(filecontent(filename), "CVE-2019-8457")).To(BeTrue()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Expect(strings.Contains(filecontent(filename), "CVE-2019-8457")).To(BeTrue()) | |
output := filecontent(filename) | |
Expect(output).To(ContainSubstring("CVE-2019-8457")) |
cmd/image-processing/main_test.go
Outdated
}) | ||
}) | ||
|
||
It("should run vulnerability scanning on a image if it is already pushed by the strategy", func() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It("should run vulnerability scanning on a image if it is already pushed by the strategy", func() { | |
It("should run vulnerability scanning on an image that is already pushed by the strategy", func() { |
cmd/image-processing/main_test.go
Outdated
"--vuln-settings", vulnSettings.String(), | ||
"--result-file-image-vulnerabilities", filename, | ||
)).ToNot(HaveOccurred()) | ||
Expect(strings.Contains(filecontent(filename), "CVE-2019-12900")).To(BeTrue()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Expect(strings.Contains(filecontent(filename), "CVE-2019-12900")).To(BeTrue()) | |
output := filecontent(filename) | |
Expect(output).To(ContainSubstring("CVE-2019-12900")) |
pkg/config/config.go
Outdated
@@ -103,6 +106,7 @@ type Config struct { | |||
Controllers Controllers | |||
KubeAPIOptions KubeAPIOptions | |||
GitRewriteRule bool | |||
VulnerabilityCountLimit string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be a number. The error returned by SetConfigFromEnv will cause the controller to panic and that's the desired behavior for invalid values.
pkg/image/vulnerability_scan.go
Outdated
cmd := exec.CommandContext(ctx, "trivy", trivyArgs...) | ||
|
||
// Print the command to be executed | ||
log.Println(cmd.String()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would print the password, correct? If so, is a no-go.
|
||
if failedContainer.Name == "step-image-processing" && exitCode == 22 { | ||
reason = buildv1beta1.BuildRunStateVulnerabilitiesFound | ||
message = fmt.Sprintf("Vulnerabilities have been found in the image which can be seen in the buildrun status. For detailed information,see kubectl --namespace %s logs %s --container=%s", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will there be reasonable output in the container logs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really, just the vulnerabilities list. In case trivy command fails, it will print an error, but in that case exit code won't be 22.
// Generate a pod with the status to be evicted | ||
failedTaskRunEvictedPod := corev1.Pod{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pls adjust
pkg/validate/output.go
Outdated
severityStr := *b.Build.Spec.Output.VulnerabilityScan.Ignore.Severity | ||
if !isValidSeverity(severityStr) { | ||
b.Build.Status.Reason = build.BuildReasonPtr(build.VulnerabilityScanSeverityNotValid) | ||
b.Build.Status.Message = pointer.String("output vulnerability scan severity is invalid, must be a comma separated combination of these values: low | medium | high | critical") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Message is not correct.
313ea2d
to
9badf96
Compare
- Add vulnerability scanning options in build and buildrun types in v1alpha1 and v1beta1 - Changes for conversion to v1beta1
9badf96
to
6aaee06
Compare
- implement vulnerability scanning using trivy - list vulnerabilities in buildrun output fix failure details
6aaee06
to
4cdc36e
Compare
Looks mostly good @karanibm6. I put a few small changes in karanibm6#37. Please check. |
…scanning Sascha add vulnerability scanning
Changes
Implementation of this SHIP : https://github.com/shipwright-io/community/blob/main/ships/0033-build-output-vulnerability-scanning.md#build-output-vulnerability-scanning
Fixes #1394
Submitter Checklist
See the contributor guide
for details on coding conventions, github and prow interactions, and the code review process.
Release Notes