示例#1
0
        public void SaveAuditReport(string suite, string database)
        {
            bool VersionLessThan(string version1, string version2)
            {
                try
                {
                    _processRunner.RunShell($"dpkg --compare-versions \"{version1}\" \"lt\" \"{version2}\"", new RunnerOptions
                    {
                        LogCommandOnError = false
                    });
                    return(true);
                }
                catch (Exception)
                {
                    return(false);
                }
            }

            // Make sure dpkg --compare-versions works
            if (!VersionLessThan("1", "2") || VersionLessThan("2", "1"))
            {
                throw new Exception("dpkg --compare-versions appears to not be working.");
            }

            var packageName = "ansible";

            var securityDb = new SecurityDb(database);

            var imageLock = GetImageLock();

            var auditReport = new AuditReport();

            foreach (var package in imageLock.InstalledPackages)
            {
                var sourcePackage = package.Value.Source;
                if (sourcePackage == null || sourcePackage.Name.IsNullOrEmpty() ||
                    sourcePackage.Version.IsNullOrEmpty())
                {
                    continue;
                }

                // Here is a description of how these issues are associated with versions/releases.
                // 1. If a package note has no release, it means that package note applies to all versions.
                // 2. If that package note has a fixed version of "0", it means that it isn't affected.
                // 3. If the package note has a fixed version of null, it means that it is affected (or hasn't been determined yet).
                // Then, if there is a package note for a specific release, it overrides 1-3 on a per-suite level.
                var bugNames = securityDb.GetPackageNotesForPackage(sourcePackage.Name).Select(x => x.BugName).Distinct().ToList();

                foreach (var bugName in bugNames)
                {
                    var packageNote = securityDb.GetPackageNoteForBugInSuite(sourcePackage.Name, bugName, suite);
                    if (packageNote == null)
                    {
                        packageNote = securityDb.GetPackageNoteForBugInAllSuites(sourcePackage.Name, bugName);
                    }

                    if (packageNote == null)
                    {
                        continue;
                    }

                    if (packageNote.FixedVersion == "0")
                    {
                        // Explicitly marked as "not affected!"
                        continue;
                    }

                    void TrackBug()
                    {
                        var auditSourcePackage = auditReport.Sources.SingleOrDefault(x =>
                                                                                     x.Name == sourcePackage.Name && x.Version == sourcePackage.Version);

                        if (auditSourcePackage == null)
                        {
                            auditSourcePackage = new AuditReport.AuditSourcePackage
                            {
                                Name    = sourcePackage.Name,
                                Version = sourcePackage.Version
                            };
                            auditReport.Sources.Add(auditSourcePackage);
                        }
                        auditSourcePackage.Binaries[package.Key] = package.Value.Version;

                        if (auditSourcePackage.Vulnerabilities.Any(x => x.Name == bugName))
                        {
                            return;
                        }

                        var bug     = securityDb.GetBug(packageNote.BugName);
                        var nvdData = securityDb.GetNvdData(bug.Name);

                        var vulnerability = new AuditReport.Vulnerability
                        {
                            Name        = packageNote.BugName,
                            Description = bug.Description,
                            Severity    = packageNote.Urgency
                        };

                        if (nvdData != null)
                        {
                            vulnerability.Description = nvdData.CveDescription;
                            vulnerability.NvdSeverity = nvdData.Severity;
                        }

                        if (vulnerability.Name.StartsWith("DSA") || vulnerability.Name.StartsWith("DLA"))
                        {
                            var references = securityDb.GetReferences(bug.Name);
                            if (references.Count > 0)
                            {
                                vulnerability.References = references;
                            }
                        }

                        vulnerability.FixedVersion = packageNote.FixedVersion;
                        if (string.IsNullOrEmpty(vulnerability.FixedVersion))
                        {
                            vulnerability.FixedVersion = "NONE";
                        }

                        var noDsa = securityDb.GetNoDsaInfoForPackage(sourcePackage.Name, bugName, suite);

                        if (noDsa != null)
                        {
                            vulnerability.NoDsa = new AuditReport.NoDsa
                            {
                                Comment = string.IsNullOrEmpty(noDsa.Comment) ? null : noDsa.Comment,
                                Reason  = string.IsNullOrEmpty(noDsa.Reason) ? null : noDsa.Reason
                            };
                        }

                        var bugNotes = securityDb.GetBugNotes(bug.Name);

                        var notes        = new List <string>();
                        var packageRegex = new Regex(@"^(?:\[([a-z]+)\]\s)?-\s([A-Za-z0-9:.+-]+)\s+<([a-z-]+)>\s*(?:\s\((.*)\))?$", RegexOptions.Compiled);

                        foreach (var bugNote in bugNotes)
                        {
                            var match = packageRegex.Match(bugNote.Comment);
                            if (match.Success)
                            {
                                continue;
                            }

                            notes.Add(bugNote.Comment);
                        }

                        if (notes.Count > 0)
                        {
                            vulnerability.Notes = notes;
                        }

                        auditSourcePackage.Vulnerabilities.Add(vulnerability);
                    }

                    if (string.IsNullOrEmpty(packageNote.FixedVersion))
                    {
                        // Marked as affected, with no fixed version.
                        TrackBug();
                    }
                    else
                    {
                        // Has a fixed version.
                        if (VersionLessThan(package.Value.Version.Version, packageNote.FixedVersion))
                        {
                            // And we don't have it!
                            TrackBug();
                        }
                    }
                }
            }

            var file = Path.Combine(_workspaceConfig.RootDirectory, "debian-audit.json");

            if (File.Exists(file))
            {
                File.Delete(file);
            }
            File.WriteAllText(file, JsonConvert.SerializeObject(auditReport, _jsonSerializerSettings));
        }