Skip to content

Commit cc37d12

Browse files
luhringjonasagx
authored andcommitted
Add support for "file" source type in syftjson unmarshaling (anchore#750)
* Add tests for image and directory syftjson source Signed-off-by: Dan Luhring <dan+github@luhrings.com> * Add failing test case for file source unmarshaling Signed-off-by: Dan Luhring <dan+github@luhrings.com> * Fix file source unmarshaling Signed-off-by: Dan Luhring <dan+github@luhrings.com> * Add test case for unknown source type Signed-off-by: Dan Luhring <dan+github@luhrings.com>
1 parent 35be488 commit cc37d12

File tree

2 files changed

+137
-1
lines changed

2 files changed

+137
-1
lines changed

internal/formats/syftjson/model/source.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func (s *Source) UnmarshalJSON(b []byte) error {
3030
s.Type = unpacker.Type
3131

3232
switch s.Type {
33-
case "directory":
33+
case "directory", "file":
3434
if target, err := strconv.Unquote(string(unpacker.Target)); err == nil {
3535
s.Target = target
3636
} else {
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
package model
2+
3+
import (
4+
"encoding/json"
5+
"testing"
6+
7+
"github.com/anchore/syft/syft/source"
8+
9+
"github.com/google/go-cmp/cmp"
10+
11+
"github.com/stretchr/testify/assert"
12+
)
13+
14+
func TestSource_UnmarshalJSON(t *testing.T) {
15+
cases := []struct {
16+
name string
17+
input []byte
18+
expectedSource *Source
19+
errAssertion assert.ErrorAssertionFunc
20+
}{
21+
{
22+
name: "directory",
23+
input: []byte(`{
24+
"type": "directory",
25+
"target":"/var/lib/foo"
26+
}`),
27+
expectedSource: &Source{
28+
Type: "directory",
29+
Target: "/var/lib/foo",
30+
},
31+
errAssertion: assert.NoError,
32+
},
33+
{
34+
name: "image",
35+
input: []byte(`{
36+
"type": "image",
37+
"target": {
38+
"userInput": "alpine:3.10",
39+
"imageID": "sha256:e7b300aee9f9bf3433d32bc9305bfdd22183beb59d933b48d77ab56ba53a197a",
40+
"manifestDigest": "sha256:e515aad2ed234a5072c4d2ef86a1cb77d5bfe4b11aa865d9214875734c4eeb3c",
41+
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
42+
"tags": [],
43+
"imageSize": 5576169,
44+
"layers": [
45+
{
46+
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
47+
"digest": "sha256:9fb3aa2f8b8023a4bebbf92aa567caf88e38e969ada9f0ac12643b2847391635",
48+
"size": 5576169
49+
}
50+
],
51+
"manifest": "ewogICAic2NoZW1hVmVyc2lvbiI6IDIsCiAgICJtZWRpYVR5cGUiOiAiYXBwbGljYXRpb24vdm5kLmRvY2tlci5kaXN0cmlidXRpb24ubWFuaWZlc3QudjIranNvbiIsCiAgICJjb25maWciOiB7CiAgICAgICJtZWRpYVR5cGUiOiAiYXBwbGljYXRpb24vdm5kLmRvY2tlci5jb250YWluZXIuaW1hZ2UudjEranNvbiIsCiAgICAgICJzaXplIjogMTQ3MiwKICAgICAgImRpZ2VzdCI6ICJzaGEyNTY6ZTdiMzAwYWVlOWY5YmYzNDMzZDMyYmM5MzA1YmZkZDIyMTgzYmViNTlkOTMzYjQ4ZDc3YWI1NmJhNTNhMTk3YSIKICAgfSwKICAgImxheWVycyI6IFsKICAgICAgewogICAgICAgICAibWVkaWFUeXBlIjogImFwcGxpY2F0aW9uL3ZuZC5kb2NrZXIuaW1hZ2Uucm9vdGZzLmRpZmYudGFyLmd6aXAiLAogICAgICAgICAic2l6ZSI6IDI3OTgzMzgsCiAgICAgICAgICJkaWdlc3QiOiAic2hhMjU2OjM5NmMzMTgzNzExNmFjMjkwNDU4YWZjYjkyOGY2OGI2Y2MxYzdiZGQ2OTYzZmM3MmY1MmYzNjVhMmE4OWMxYjUiCiAgICAgIH0KICAgXQp9",
52+
"config": "eyJhcmNoaXRlY3R1cmUiOiJhbWQ2NCIsImNvbmZpZyI6eyJIb3N0bmFtZSI6IiIsIkRvbWFpbm5hbWUiOiIiLCJVc2VyIjoiIiwiQXR0YWNoU3RkaW4iOmZhbHNlLCJBdHRhY2hTdGRvdXQiOmZhbHNlLCJBdHRhY2hTdGRlcnIiOmZhbHNlLCJUdHkiOmZhbHNlLCJPcGVuU3RkaW4iOmZhbHNlLCJTdGRpbk9uY2UiOmZhbHNlLCJFbnYiOlsiUEFUSD0vdXNyL2xvY2FsL3NiaW46L3Vzci9sb2NhbC9iaW46L3Vzci9zYmluOi91c3IvYmluOi9zYmluOi9iaW4iXSwiQ21kIjpbIi9iaW4vc2giXSwiSW1hZ2UiOiJzaGEyNTY6ZWIyMDgwYzQ1NWU5NGMyMmFlMzViM2FlZjllMDc4YzQ5MmEwMDc5NTQxMmUwMjZlNGQ2YjQxZWY2NGJjN2RkOCIsIlZvbHVtZXMiOm51bGwsIldvcmtpbmdEaXIiOiIiLCJFbnRyeXBvaW50IjpudWxsLCJPbkJ1aWxkIjpudWxsLCJMYWJlbHMiOm51bGx9LCJjb250YWluZXIiOiJmZGI3ZTgwZTMzMzllOGQwNTk5MjgyZTYwNmM5MDdhYTU4ODFlZTRjNjY4YTY4MTM2MTE5ZTZkZmFjNmNlM2E0IiwiY29udGFpbmVyX2NvbmZpZyI6eyJIb3N0bmFtZSI6ImZkYjdlODBlMzMzOSIsIkRvbWFpbm5hbWUiOiIiLCJVc2VyIjoiIiwiQXR0YWNoU3RkaW4iOmZhbHNlLCJBdHRhY2hTdGRvdXQiOmZhbHNlLCJBdHRhY2hTdGRlcnIiOmZhbHNlLCJUdHkiOmZhbHNlLCJPcGVuU3RkaW4iOmZhbHNlLCJTdGRpbk9uY2UiOmZhbHNlLCJFbnYiOlsiUEFUSD0vdXNyL2xvY2FsL3NiaW46L3Vzci9sb2NhbC9iaW46L3Vzci9zYmluOi91c3IvYmluOi9zYmluOi9iaW4iXSwiQ21kIjpbIi9iaW4vc2giLCItYyIsIiMobm9wKSAiLCJDTUQgW1wiL2Jpbi9zaFwiXSJdLCJJbWFnZSI6InNoYTI1NjplYjIwODBjNDU1ZTk0YzIyYWUzNWIzYWVmOWUwNzhjNDkyYTAwNzk1NDEyZTAyNmU0ZDZiNDFlZjY0YmM3ZGQ4IiwiVm9sdW1lcyI6bnVsbCwiV29ya2luZ0RpciI6IiIsIkVudHJ5cG9pbnQiOm51bGwsIk9uQnVpbGQiOm51bGwsIkxhYmVscyI6e319LCJjcmVhdGVkIjoiMjAyMS0wNC0xNFQxOToyMDowNS4zMzgzOTc3NjFaIiwiZG9ja2VyX3ZlcnNpb24iOiIxOS4wMy4xMiIsImhpc3RvcnkiOlt7ImNyZWF0ZWQiOiIyMDIxLTA0LTE0VDE5OjIwOjA0Ljk4NzIxOTEyNFoiLCJjcmVhdGVkX2J5IjoiL2Jpbi9zaCAtYyAjKG5vcCkgQUREIGZpbGU6YzUzNzdlYWE5MjZiZjQxMmRkOGQ0YTA4YjBhMWYyMzk5Y2ZkNzA4NzQzNTMzYjBhYTAzYjUzZDE0Y2I0YmI0ZSBpbiAvICJ9LHsiY3JlYXRlZCI6IjIwMjEtMDQtMTRUMTk6MjA6MDUuMzM4Mzk3NzYxWiIsImNyZWF0ZWRfYnkiOiIvYmluL3NoIC1jICMobm9wKSAgQ01EIFtcIi9iaW4vc2hcIl0iLCJlbXB0eV9sYXllciI6dHJ1ZX1dLCJvcyI6ImxpbnV4Iiwicm9vdGZzIjp7InR5cGUiOiJsYXllcnMiLCJkaWZmX2lkcyI6WyJzaGEyNTY6OWZiM2FhMmY4YjgwMjNhNGJlYmJmOTJhYTU2N2NhZjg4ZTM4ZTk2OWFkYTlmMGFjMTI2NDNiMjg0NzM5MTYzNSJdfX0=",
53+
"repoDigests": [
54+
"index.docker.io/library/alpine@sha256:451eee8bedcb2f029756dc3e9d73bab0e7943c1ac55cff3a4861c52a0fdd3e98"
55+
]
56+
}
57+
}`),
58+
expectedSource: &Source{
59+
Type: "image",
60+
Target: source.ImageMetadata{
61+
UserInput: "alpine:3.10",
62+
ID: "sha256:e7b300aee9f9bf3433d32bc9305bfdd22183beb59d933b48d77ab56ba53a197a",
63+
ManifestDigest: "sha256:e515aad2ed234a5072c4d2ef86a1cb77d5bfe4b11aa865d9214875734c4eeb3c",
64+
MediaType: "application/vnd.docker.distribution.manifest.v2+json",
65+
Tags: []string{},
66+
Size: 5576169,
67+
Layers: []source.LayerMetadata{
68+
{
69+
MediaType: "application/vnd.docker.image.rootfs.diff.tar.gzip",
70+
Digest: "sha256:9fb3aa2f8b8023a4bebbf92aa567caf88e38e969ada9f0ac12643b2847391635",
71+
Size: 5576169,
72+
},
73+
},
74+
RawManifest: []byte(`{
75+
"schemaVersion": 2,
76+
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
77+
"config": {
78+
"mediaType": "application/vnd.docker.container.image.v1+json",
79+
"size": 1472,
80+
"digest": "sha256:e7b300aee9f9bf3433d32bc9305bfdd22183beb59d933b48d77ab56ba53a197a"
81+
},
82+
"layers": [
83+
{
84+
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
85+
"size": 2798338,
86+
"digest": "sha256:396c31837116ac290458afcb928f68b6cc1c7bdd6963fc72f52f365a2a89c1b5"
87+
}
88+
]
89+
}`),
90+
RawConfig: []byte(`{"architecture":"amd64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh"],"Image":"sha256:eb2080c455e94c22ae35b3aef9e078c492a00795412e026e4d6b41ef64bc7dd8","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"fdb7e80e3339e8d0599282e606c907aa5881ee4c668a68136119e6dfac6ce3a4","container_config":{"Hostname":"fdb7e80e3339","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"/bin/sh\"]"],"Image":"sha256:eb2080c455e94c22ae35b3aef9e078c492a00795412e026e4d6b41ef64bc7dd8","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2021-04-14T19:20:05.338397761Z","docker_version":"19.03.12","history":[{"created":"2021-04-14T19:20:04.987219124Z","created_by":"/bin/sh -c #(nop) ADD file:c5377eaa926bf412dd8d4a08b0a1f2399cfd708743533b0aa03b53d14cb4bb4e in / "},{"created":"2021-04-14T19:20:05.338397761Z","created_by":"/bin/sh -c #(nop) CMD [\"/bin/sh\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:9fb3aa2f8b8023a4bebbf92aa567caf88e38e969ada9f0ac12643b2847391635"]}}`),
91+
RepoDigests: []string{
92+
"index.docker." +
93+
"io/library/alpine@sha256:451eee8bedcb2f029756dc3e9d73bab0e7943c1ac55cff3a4861c52a0fdd3e98",
94+
},
95+
},
96+
},
97+
errAssertion: assert.NoError,
98+
},
99+
{
100+
name: "file",
101+
input: []byte(`{
102+
"type": "file",
103+
"target":"/var/lib/foo/go.mod"
104+
}`),
105+
expectedSource: &Source{
106+
Type: "file",
107+
Target: "/var/lib/foo/go.mod",
108+
},
109+
errAssertion: assert.NoError,
110+
},
111+
{
112+
name: "unknown source type",
113+
input: []byte(`{
114+
"type": "unknown-thing",
115+
"target":"/var/lib/foo"
116+
}`),
117+
expectedSource: &Source{
118+
Type: "unknown-thing",
119+
},
120+
errAssertion: assert.Error,
121+
},
122+
}
123+
124+
for _, testCase := range cases {
125+
t.Run(testCase.name, func(t *testing.T) {
126+
source := new(Source)
127+
128+
err := json.Unmarshal(testCase.input, source)
129+
130+
testCase.errAssertion(t, err)
131+
if diff := cmp.Diff(testCase.expectedSource, source); diff != "" {
132+
t.Errorf("unexpected result from Source unmarshaling (-want +got)\n%s", diff)
133+
}
134+
})
135+
}
136+
}

0 commit comments

Comments
 (0)