public override async Task <IEnumerable <VulnerabilityInfo> > GetVulnerabilitiesAsync(IVulnerabilitySourceContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var packages = context.Packages.Select(PackageId.TryCreate).Where(p => p != null).ToArray();

            if (!packages.Any())
            {
                return(Enumerable.Empty <VulnerabilityInfo>());
            }

            using (var client = new HttpClient())
                using (var content = new StringContent(JsonConvert.SerializeObject(packages), InedoLib.UTF8Encoding, "application/json"))
                    using (var response = await client.PostAsync("https://ossindex.net/v2.0/package", content))
                    {
                        response.EnsureSuccessStatusCode();

                        return(JsonConvert.DeserializeObject <IEnumerable <PackageVulnerabilities> >(await response.Content.ReadAsStringAsync())
                               .SelectMany(p => p.Vulnerabilities.Select(v => v.GetInfo(p, packages))));
                    }
        }
예제 #2
0
        public override async Task <IEnumerable <VulnerabilityInfo> > GetVulnerabilitiesAsync(IVulnerabilitySourceContext context)
        {
            var serializer           = new JsonSerializer();
            var layersApi            = ApiUrl.Trim('/') + "/v1/layers";
            var vulnerabilitesApiUrl = ApiUrl.Trim('/') + "/v1/layers/{0}?features&vulnerabilities";



            var vulnerabilityInfos = new List <VulnerabilityInfo>();

            foreach (var blob in context.Blobs.Where(b => !b.MediaType.EndsWith("json", StringComparison.OrdinalIgnoreCase)))
            {
                var postRequest = this.CreatePostWebRequest(layersApi);
                var response    = await this.PushLayerToClair(serializer, postRequest, blob);

                if (response != null)
                {
                    var vResponse = await this.GetVulnerabilitesFromClair(serializer, vulnerabilitesApiUrl, blob, response);

                    if (vResponse?.Layer?.Features?.Any(f => f?.Vulnerabilities?.Any(v => v != null) ?? false) != null)
                    {
                        var vulnerableFeatures = vResponse.Layer.Features.Where(f => f.Vulnerabilities?.Any() ?? false);
                        foreach (var vulnerableFeature in vulnerableFeatures)
                        {
                            foreach (var vulnerability in vulnerableFeature.Vulnerabilities)
                            {
                                vulnerabilityInfos.Add(new ClairVulnerabilityInfo(this.BuildId(vulnerableFeature), blob.FeedType, blob.Digest, vulnerability.Name, this.BuildDescription(vulnerableFeature, vulnerability)));
                            }
                        }
                    }
                }
            }

            return(vulnerabilityInfos);
        }
예제 #3
0
        public override async IAsyncEnumerable <VulnerabilityInfo> GetVulnerabilitiesAsync(IVulnerabilitySourceContext context, [EnumeratorCancellation] CancellationToken cancellationToken = default)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }
            using (var client = this.GetHttpClient())
            {
                var serializer = new JsonSerializer();

                var receivedVulnerabilities = new Dictionary <string, OSSVulnerability>();

                foreach (var chunk in GetCoordinateChunks(context.Packages))
                {
                    int retries = 0;
Retry:


                    using (var content = getChunkContent(chunk))
                        using (var response = await client.PostAsync("https://ossindex.sonatype.org/api/v3/component-report", content, cancellationToken))
                        {
                            if ((int)response.StatusCode == 429 && retries < 5)
                            {
                                this.LogWarning($"Detected rate limiting. Waiting five minutes before retrying. Attempt {(retries + 1)} of 5.");
                                await Task.Delay(TimeSpan.FromMinutes(5), cancellationToken);

                                retries++;
                                goto Retry;
                            }

                            if (!response.IsSuccessStatusCode)
                            {
                                this.LogError("OSS Index returned failure error code: " + (int)response.StatusCode);
                                this.LogDebug("Content of response: " + await response.Content.ReadAsStringAsync(cancellationToken));
                                yield break;
                            }
                            using (var responseStream = new BufferedStream(await response.Content.ReadAsStreamAsync(cancellationToken)))
                                using (var textReader = new StreamReader(responseStream, InedoLib.UTF8Encoding))
                                    using (var jsonTextReader = new JsonTextReader(textReader))
                                    {
                                        var pvs = serializer.Deserialize <IEnumerable <PackageVulnerabilities> >(jsonTextReader);
                                        this.LogDebug($"Request returned {pvs.Count()} vulnerability records.");

                                        foreach (var pv in pvs)
                                        {
                                            var match = CoordinateRegex.Match(pv.Coordinates);
                                            if (!match.Success)
                                            {
                                                this.LogWarning($"Unable to parse returned package coordinate string '{pv.Coordinates}'");
                                                continue;
                                            }

                                            var feedType = ParseFeedType(match.Groups[1].Value);
                                            if (feedType == null)
                                            {
                                                this.LogWarning($"Unable to determine feed type for returned package coordinate string '{pv.Coordinates}'");
                                                continue;
                                            }

                                            var packageName    = Uri.UnescapeDataString(match.Groups[2].Value);
                                            var packageVersion = match.Groups[3].Value;

                                            foreach (var v in pv.Vulnerabilities)
                                            {
                                                if (!receivedVulnerabilities.TryGetValue(v.Id, out var vulnerability))
                                                {
                                                    vulnerability = new OSSVulnerability(v.Id, v.Title, v.Description, v.CVSSScore, v.Reference);
                                                    receivedVulnerabilities.Add(v.Id, vulnerability);
                                                }

                                                vulnerability.AddPackageVersion(feedType.Value, packageName, packageVersion);
                                            }
                                        }
                                    }
                        }
                }

                foreach (var vulnInfo in receivedVulnerabilities.Values.SelectMany(v => v.GetVulnerabilityInfos()))
                {
                    yield return(vulnInfo);
                }
            }

            HttpContent getChunkContent(string[] chunk)
            {
                var stream = new MemoryStream();

                using (var textWriter = new StreamWriter(stream, InedoLib.UTF8Encoding, 16, true))
                    using (var jsonWriter = new JsonTextWriter(textWriter))
                    {
                        jsonWriter.WriteStartObject();
                        jsonWriter.WritePropertyName("coordinates");
                        jsonWriter.WriteStartArray();
                        foreach (var c in chunk)
                        {
                            jsonWriter.WriteValue(c);
                        }
                        jsonWriter.WriteEndArray();
                        jsonWriter.WriteEndObject();
                    }

                stream.Position = 0;
                return(new StreamContent(stream)
                {
                    Headers =
                    {
                        ContentType = new MediaTypeHeaderValue("application/vnd.ossindex.component-report-request.v1+json")
                    }
                });
            }
        }