@@ -16,6 +16,7 @@ import (
16
16
"github.com/google/go-containerregistry/pkg/v1/remote/transport"
17
17
"github.com/quay/claircore"
18
18
"github.com/quay/zlog"
19
+ spdxtools "github.com/spdx/tools-golang/spdx/v2/v2_3"
19
20
"github.com/tomnomnom/linkheader"
20
21
21
22
"github.com/quay/clair/v4/cmd"
@@ -105,7 +106,28 @@ var (
105
106
errNovelManifest = errors .New ("manifest unknown to the system" )
106
107
)
107
108
108
- func (c * Client ) IndexReport (ctx context.Context , id claircore.Digest , m * claircore.Manifest ) error {
109
+ func (c * Client ) SPDXReport (ctx context.Context , id claircore.Digest , m * claircore.Manifest ) (* spdxtools.Document , error ) {
110
+ var report = spdxtools.Document {}
111
+ err := c .GetIndexReport (ctx , id , m , & report , "application/spdx+json" )
112
+ if err != nil {
113
+ return nil , err
114
+ }
115
+ return & report , nil
116
+ }
117
+
118
+ func (c * Client ) IndexReport (ctx context.Context , id claircore.Digest , m * claircore.Manifest ) (* claircore.IndexReport , error ) {
119
+ var report = claircore.IndexReport {}
120
+ err := c .GetIndexReport (ctx , id , m , & report , "application/json" )
121
+ if err != nil {
122
+ return nil , err
123
+ }
124
+ if ! report .Success && report .Err != "" {
125
+ return nil , errors .New ("indexer error: " + report .Err )
126
+ }
127
+ return & report , nil
128
+ }
129
+
130
+ func (c * Client ) GetIndexReport (ctx context.Context , id claircore.Digest , m * claircore.Manifest , dest interface {}, mediaType string ) error {
109
131
var (
110
132
req * http.Request
111
133
res * http.Response
@@ -121,6 +143,7 @@ func (c *Client) IndexReport(ctx context.Context, id claircore.Digest, m *clairc
121
143
if err != nil {
122
144
return err
123
145
}
146
+ req .Header .Add ("Accept" , mediaType )
124
147
res , err = c .client .Do (req )
125
148
if err != nil {
126
149
zlog .Debug (ctx ).
@@ -130,97 +153,90 @@ func (c *Client) IndexReport(ctx context.Context, id claircore.Digest, m *clairc
130
153
return err
131
154
}
132
155
defer res .Body .Close ()
133
- ev := zlog .Debug (ctx ).
156
+ zlog .Debug (ctx ).
134
157
Str ("method" , res .Request .Method ).
135
158
Str ("path" , res .Request .URL .Path ).
136
159
Str ("status" , res .Status )
137
- if ev .Enabled () && res .ContentLength > 0 && res .ContentLength <= 256 {
138
- var buf bytes.Buffer
139
- buf .ReadFrom (io .LimitReader (res .Body , 256 ))
140
- ev .Stringer ("body" , & buf )
141
- }
142
- ev .Send ()
143
- switch res .StatusCode {
144
- case http .StatusNotFound , http .StatusOK :
145
- case http .StatusNotModified :
146
- return nil
147
- default :
148
- return fmt .Errorf ("unexpected return status: %d" , res .StatusCode )
149
- }
150
160
151
- if m == nil {
152
- ev := zlog .Debug (ctx ).
153
- Stringer ("manifest" , id )
154
- if res .StatusCode == http .StatusNotFound {
155
- ev .Msg ("don't have needed manifest" )
156
- return errNovelManifest
161
+ var rd io.Reader
162
+ switch res .StatusCode {
163
+ case http .StatusOK , http .StatusNotModified :
164
+ rd = res .Body
165
+ case http .StatusNotFound :
166
+ if m == nil {
167
+ ev := zlog .Debug (ctx ).
168
+ Stringer ("manifest" , id )
169
+ if res .StatusCode == http .StatusNotFound {
170
+ ev .Msg ("don't have needed manifest" )
171
+ return errNovelManifest
172
+ }
173
+ ev .Msg ("manifest may be out-of-date" )
174
+ return errNeedManifest
175
+ }
176
+ ru , err := c .host .Parse (path .Join (c .host .RequestURI (), httptransport .IndexAPIPath ))
177
+ if err != nil {
178
+ zlog .Debug (ctx ).
179
+ Err (err ).
180
+ Msg ("unable to construct index_report url" )
181
+ return err
157
182
}
158
- ev .Msg ("manifest may be out-of-date" )
159
- return errNeedManifest
160
- }
161
- ru , err := c .host .Parse (path .Join (c .host .RequestURI (), httptransport .IndexAPIPath ))
162
- if err != nil {
163
- zlog .Debug (ctx ).
164
- Err (err ).
165
- Msg ("unable to construct index_report url" )
166
- return err
167
- }
168
183
169
- req , err = c .request (ctx , ru , http .MethodPost )
170
- if err != nil {
171
- return err
172
- }
173
- req .Body = codec .JSONReader (m )
174
- res , err = c .client .Do (req )
175
- if err != nil {
184
+ req , err = c .request (ctx , ru , http .MethodPost )
185
+ if err != nil {
186
+ return err
187
+ }
188
+ req .Header .Add ("Accept" , mediaType )
189
+ req .Body = codec .JSONReader (m )
190
+ res , err = c .client .Do (req )
191
+ if err != nil {
192
+ zlog .Debug (ctx ).
193
+ Err (err ).
194
+ Stringer ("url" , req .URL ).
195
+ Msg ("request failed" )
196
+ return err
197
+ }
198
+ defer res .Body .Close ()
176
199
zlog .Debug (ctx ).
177
- Err (err ).
178
- Stringer ("url" , req .URL ).
179
- Msg ("request failed" )
180
- return err
181
- }
182
- defer res .Body .Close ()
183
- zlog .Debug (ctx ).
184
- Str ("method" , res .Request .Method ).
185
- Str ("path" , res .Request .URL .Path ).
186
- Str ("status" , res .Status ).
187
- Send ()
188
- switch res .StatusCode {
189
- case http .StatusOK :
190
- case http .StatusCreated :
191
- //
200
+ Str ("method" , res .Request .Method ).
201
+ Str ("path" , res .Request .URL .Path ).
202
+ Str ("status" , res .Status ).
203
+ Send ()
204
+ switch res .StatusCode {
205
+ case http .StatusOK :
206
+ case http .StatusCreated :
207
+ //
208
+ default :
209
+ return fmt .Errorf ("unexpected return status: %d" , res .StatusCode )
210
+ }
211
+ switch {
212
+ case res .ContentLength > 0 && res .ContentLength < 32 + 9 :
213
+ // Less than the size of the digest representation, something's up.
214
+ var buf bytes.Buffer
215
+ // Ignore error, because what would we do with it here?
216
+ ct , _ := buf .ReadFrom (res .Body )
217
+ zlog .Info (ctx ).
218
+ Int64 ("size" , ct ).
219
+ Stringer ("response" , & buf ).
220
+ Msg ("body seems short" )
221
+ return fmt .Errorf ("body seems short: %d bytes" , ct )
222
+ case res .ContentLength < 0 : // Streaming
223
+ fallthrough
224
+ default :
225
+ rd = res .Body
226
+ }
192
227
default :
193
228
return fmt .Errorf ("unexpected return status: %d" , res .StatusCode )
194
229
}
195
- var rd io.Reader
196
- switch {
197
- case res .ContentLength > 0 && res .ContentLength < 32 + 9 :
198
- // Less than the size of the digest representation, something's up.
199
- var buf bytes.Buffer
200
- // Ignore error, because what would we do with it here?
201
- ct , _ := buf .ReadFrom (res .Body )
202
- zlog .Info (ctx ).
203
- Int64 ("size" , ct ).
204
- Stringer ("response" , & buf ).
205
- Msg ("body seems short" )
206
- rd = & buf
207
- case res .ContentLength < 0 : // Streaming
208
- fallthrough
209
- default :
210
- rd = res .Body
211
- }
212
- var report claircore.IndexReport
230
+
213
231
dec := codec .GetDecoder (rd )
214
232
defer codec .PutDecoder (dec )
215
- if err := dec .Decode (& report ); err != nil {
233
+ if err := dec .Decode (& dest ); err != nil {
216
234
zlog .Debug (ctx ).
217
235
Err (err ).
218
236
Msg ("unable to decode json payload" )
219
237
return err
220
238
}
221
- if ! report .Success && report .Err != "" {
222
- return errors .New ("indexer error: " + report .Err )
223
- }
239
+
224
240
if v := res .Header .Get ("etag" ); v != "" {
225
241
ls := linkheader .ParseMultiple (res .Header [http .CanonicalHeaderKey ("link" )]).
226
242
FilterByRel ("https://projectquay.io/clair/v1/index_report" )
@@ -232,6 +248,7 @@ func (c *Client) IndexReport(ctx context.Context, id claircore.Digest, m *clairc
232
248
c .setValidator (ctx , u .Path , v )
233
249
}
234
250
}
251
+
235
252
return nil
236
253
}
237
254
0 commit comments