Skip to content
This repository was archived by the owner on Jul 18, 2025. It is now read-only.

Commit 5a09266

Browse files
authored
Merge pull request #135 from docker/add-group-issues-flag
Add support of Snyk --group-issues flag for json output
2 parents 9e56383 + f379034 commit 5a09266

6 files changed

Lines changed: 106 additions & 1 deletion

File tree

README.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,56 @@ $ docker scan --json hello-world
162162
}
163163
```
164164

165+
In addition to the `--json` flag, you can use the `--group-issues` flag to display only once a vulnerability
166+
```console
167+
$ docker scan --json --group-issues docker-scan:e2e
168+
{
169+
{
170+
"title": "Improper Check for Dropped Privileges",
171+
...
172+
"packageName": "bash",
173+
"language": "linux",
174+
"packageManager": "debian:10",
175+
"description": "## Overview\nAn issue was discovered in disable_priv_mode in shell.c in GNU Bash through 5.0 patch 11. By default, if Bash is run with its effective UID not equal to its real UID, it will drop privileges by setting its effective UID to its real UID. However, it does so incorrectly. On Linux and other systems that support \"saved UID\" functionality, the saved UID is not dropped. An attacker with command execution in the shell can use \"enable -f\" for runtime loading of a new builtin, which can be a shared object that calls setuid() and therefore regains privileges. However, binaries running with an effective UID of 0 are unaffected.\n\n## References\n- [CONFIRM](https://security.netapp.com/advisory/ntap-20200430-0003/)\n- [Debian Security Tracker](https://security-tracker.debian.org/tracker/CVE-2019-18276)\n- [GitHub Commit](https://github.com/bminor/bash/commit/951bdaad7a18cc0dc1036bba86b18b90874d39ff)\n- [MISC](http://packetstormsecurity.com/files/155498/Bash-5.0-Patch-11-Privilege-Escalation.html)\n- [MISC](https://www.youtube.com/watch?v=-wGtxJ8opa8)\n- [Ubuntu CVE Tracker](http://people.ubuntu.com/~ubuntu-security/cve/CVE-2019-18276)\n",
176+
"identifiers": {
177+
"ALTERNATIVE": [],
178+
"CVE": [
179+
"CVE-2019-18276"
180+
],
181+
"CWE": [
182+
"CWE-273"
183+
]
184+
},
185+
"severity": "low",
186+
"severityWithCritical": "low",
187+
"cvssScore": 7.8,
188+
"CVSSv3": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H/E:F",
189+
...
190+
"from": [
191+
"docker-image|docker-scan@e2e",
192+
"bash@5.0-4"
193+
],
194+
"upgradePath": [],
195+
"isUpgradable": false,
196+
"isPatchable": false,
197+
"name": "bash",
198+
"version": "5.0-4"
199+
},
200+
...
201+
"summary": "880 vulnerable dependency paths",
202+
"filesystemPolicy": false,
203+
"filtered": {
204+
"ignore": [],
205+
"patch": []
206+
},
207+
"uniqueCount": 158,
208+
"projectName": "docker-image|docker-scan",
209+
"platform": "linux/amd64",
210+
"path": "docker-scan:e2e"
211+
}
212+
```
213+
You can find all the sources of the vulnerability in the `from` section.
214+
165215
If you want to see the dependency tree of your image, you can use the `--dependency-tree` flag, to display all the dependencies before the scan result
166216
```console
167217
$ docker-image|99138c65ebc7 @ latest

cmd/docker-scan/main.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ type options struct {
7070
forceOptIn bool
7171
forceOptOut bool
7272
severity string
73+
groupIssues bool
7374
}
7475

7576
func newScanCmd(ctx context.Context, dockerCli command.Cli) *cobra.Command {
@@ -99,6 +100,7 @@ func newScanCmd(ctx context.Context, dockerCli command.Cli) *cobra.Command {
99100
cmd.Flags().BoolVar(&flags.forceOptIn, "accept-license", false, "Accept using a third party scanning provider")
100101
cmd.Flags().BoolVar(&flags.forceOptOut, "reject-license", false, "Reject using a third party scanning provider")
101102
cmd.Flags().StringVar(&flags.severity, "severity", "", "Only report vulnerabilities of provided level or higher (low|medium|high)")
103+
cmd.Flags().BoolVar(&flags.groupIssues, "group-issues", false, "Aggregate duplicated vulnerabilities and group them to a single one (requires --json)")
102104

103105
return cmd
104106
}
@@ -116,6 +118,11 @@ func configureProvider(ctx context.Context, dockerCli command.Streams, flags opt
116118
opts = append(opts, options...)
117119
if flags.jsonFormat {
118120
opts = append(opts, provider.WithJSON())
121+
if flags.groupIssues {
122+
opts = append(opts, provider.WithGroupIssues())
123+
}
124+
} else if flags.groupIssues {
125+
return nil, fmt.Errorf("--json flag is mandatory to use --group-issues flag")
119126
}
120127
if flags.dockerFilePath != "" {
121128
opts = append(opts, provider.WithDockerFile(flags.dockerFilePath))

e2e/scan_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,44 @@ func TestScanWithSeverityBadValue(t *testing.T) {
301301
Err: "--severity takes only 'low', 'medium' or 'high' values"})
302302
}
303303

304+
func TestScanWithJsonAndGroupIssues(t *testing.T) {
305+
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
306+
t.Skip("Can't run on this ci platform (windows containers or no engine installed)")
307+
}
308+
_, cleanFunction := createSnykConfFile(t, os.Getenv("E2E_TEST_AUTH_TOKEN"))
309+
defer cleanFunction()
310+
311+
cmd, configDir, cleanup := dockerCli.createTestCmd()
312+
defer cleanup()
313+
314+
createScanConfigFile(t, configDir)
315+
316+
cmd.Command = dockerCli.Command("scan", "--accept-license", "--json", "--group-issues", ImageWithVulnerabilities)
317+
output := icmd.RunCmd(cmd).Assert(t, icmd.Expected{ExitCode: 1}).Combined()
318+
assert.Assert(t, strings.Contains(output, "vulnerable dependency paths")) // beginning of the dependency tree
319+
assert.Assert(t, strings.Contains(output, `"from": [
320+
[
321+
"docker-image|alpine@3.10.0",`))
322+
}
323+
324+
func TestScanWithGroupIssues(t *testing.T) {
325+
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
326+
t.Skip("Can't run on this ci platform (windows containers or no engine installed)")
327+
}
328+
_, cleanFunction := createSnykConfFile(t, os.Getenv("E2E_TEST_AUTH_TOKEN"))
329+
defer cleanFunction()
330+
331+
cmd, configDir, cleanup := dockerCli.createTestCmd()
332+
defer cleanup()
333+
334+
createScanConfigFile(t, configDir)
335+
336+
cmd.Command = dockerCli.Command("scan", "--accept-license", "--group-issues", ImageBaseImageVulnerabilities)
337+
icmd.RunCmd(cmd).Assert(t, icmd.Expected{
338+
ExitCode: 1,
339+
Err: "--json flag is mandatory to use --group-issues flag"})
340+
}
341+
304342
func createSnykConfFile(t *testing.T, token string) (*fs.Dir, func()) {
305343
content := fmt.Sprintf(`{"api" : "%s"}`, token)
306344
homeDir := fs.NewDir(t, t.Name(),

e2e/testdata/plugin-usage.golden

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ Options:
1010
(requires --file)
1111
-f, --file string Dockerfile associated with image, provides more
1212
detailed results
13+
--group-issues Aggregate duplicated vulnerabilities and group
14+
them to a single one (requires --json)
1315
--json Output results in JSON format
1416
--login Authenticate to the scan provider using an
1517
optional token (with --token), or web base

internal/provider/snyk.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,14 @@ func WithSeverity(severity string) SnykProviderOps {
144144
}
145145
}
146146

147+
// WithGroupIssues groups same issues in a single one when using --json flag
148+
func WithGroupIssues() SnykProviderOps {
149+
return func(provider *snykProvider) error {
150+
provider.flags = append(provider.flags, "--group-issues")
151+
return nil
152+
}
153+
}
154+
147155
func (s *snykProvider) Authenticate(token string) error {
148156
if token != "" {
149157
if _, err := uuid.Parse(token); err != nil {

vars.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Pinned Versions
2-
SNYK_DESKTOP_VERSION=1.424.4
2+
SNYK_DESKTOP_VERSION=1.432.0
33
SNYK_USER_VERSION=1.425.0
44
SNYK_OLD_VERSION=1.382.1
55
GO_VERSION=1.15.0

0 commit comments

Comments
 (0)