github.com/quay/claircore@v1.5.28/rhel/internal/containerapi/containerapi.go (about) 1 // Package containerapi is a minimal client around the Red Hat Container API. 2 package containerapi 3 4 import ( 5 "context" 6 "encoding/json" 7 "fmt" 8 "io" 9 "net/http" 10 "net/url" 11 "path" 12 "strings" 13 14 "github.com/quay/zlog" 15 ) 16 17 type containerImages struct { 18 Images []containerImage `json:"data"` 19 } 20 type containerImage struct { 21 CPEs []string `json:"cpe_ids"` 22 ParsedData parsedData `json:"parsed_data"` 23 } 24 type parsedData struct { 25 Architecture string `json:"architecture"` 26 Labels []label `json:"labels"` 27 } 28 type label struct { 29 Name string `json:"name"` 30 Value string `json:"value"` 31 } 32 33 // ContainerAPI gets container metadata from Red Hat's API. 34 type ContainerAPI struct { 35 Client *http.Client 36 Root *url.URL 37 } 38 39 // GetCPEs fetches CPE information for given build from Red Hat Container API. 40 func (c *ContainerAPI) GetCPEs(ctx context.Context, nvr, arch string) ([]string, error) { 41 uri, err := c.Root.Parse(path.Join("v1/images/nvr/", nvr)) 42 if err != nil { 43 return nil, err 44 } 45 req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil) 46 if err != nil { 47 return nil, err 48 } 49 50 zlog.Debug(ctx). 51 Str("uri", uri.String()). 52 Msg("making container API request") 53 res, err := c.Client.Do(req) 54 if err != nil { 55 return nil, err 56 } 57 defer res.Body.Close() 58 if res.StatusCode != http.StatusOK { 59 var b strings.Builder 60 if _, err := io.Copy(&b, res.Body); err != nil { 61 zlog.Warn(ctx).Err(err).Msg("additional error while reading response") 62 } else { 63 zlog.Warn(ctx).Str("response", b.String()).Msg("received error response") 64 } 65 return nil, fmt.Errorf("rhel: unexpected response: %d %s", res.StatusCode, res.Status) 66 } 67 68 var ci containerImages 69 if err := json.NewDecoder(res.Body).Decode(&ci); err != nil { 70 return nil, err 71 } 72 for _, image := range ci.Images { 73 for _, label := range image.ParsedData.Labels { 74 if label.Name == "architecture" { 75 if label.Value == arch { 76 return image.CPEs, nil 77 } 78 } 79 } 80 } 81 return nil, nil 82 }