/// <summary>
        /// Analyzes a single Project file for NuGet package references.
        /// </summary>
        /// <param name="projectFilePath"></param>
        /// <returns></returns>
        public async Task <HashSet <NugetPackage> > GetProjectNugetPackagesAsync(string projectFilePath, string baseIntermediateOutputPath, bool excludeTestProjects)
        {
            if (!_fileSystem.File.Exists(projectFilePath))
            {
                Console.Error.WriteLine($"Project file \"{projectFilePath}\" does not exist");
                return(new HashSet <NugetPackage>());
            }

            var packages = new HashSet <NugetPackage>();

            Console.WriteLine();
            Console.WriteLine($"» Analyzing: {projectFilePath}");

            if (excludeTestProjects && IsTestProject(projectFilePath))
            {
                Console.WriteLine($"Skipping: {projectFilePath}");
                return(new HashSet <NugetPackage>());
            }

            Console.WriteLine("  Attempting to restore packages");
            var restoreResult = _dotnetUtilsService.Restore(projectFilePath);

            if (restoreResult.Success)
            {
                var assetsFilename = _fileSystem.Path.Combine(GetProjectProperty(projectFilePath, baseIntermediateOutputPath), "project.assets.json");
                if (!File.Exists(assetsFilename))
                {
                    Console.WriteLine($"File not found: \"{assetsFilename}\", \"{projectFilePath}\" ");
                }
                packages.UnionWith(_projectAssetsFileService.GetNugetPackages(assetsFilename));
            }
            else
            {
                Console.WriteLine("Dotnet restore failed:");
                Console.WriteLine(restoreResult.ErrorMessage);
                throw new DotnetRestoreException($"Dotnet restore failed with message: {restoreResult.ErrorMessage}");
            }

            // if there are no project file package references look for a packages.config
            if (!packages.Any())
            {
                Console.WriteLine("  No packages found");
                var directoryPath = _fileSystem.Path.GetDirectoryName(projectFilePath);
                var packagesPath  = _fileSystem.Path.Combine(directoryPath, "packages.config");
                if (_fileSystem.File.Exists(packagesPath))
                {
                    Console.WriteLine("  Found packages.config. Will attempt to process");
                    packages = await _packagesFileService.GetNugetPackagesAsync(packagesPath).ConfigureAwait(false);
                }
            }
            return(packages);
        }
Ejemplo n.º 2
0
        async Task <int> OnExecuteAsync()
        {
            if (version)
            {
                Console.WriteLine(Assembly.GetExecutingAssembly().GetName().Version?.ToString());
                return(0);
            }

            Console.WriteLine();

            // check parameter values
            if (string.IsNullOrEmpty(SolutionOrProjectFile))
            {
                Console.Error.WriteLine($"A path is required");
                return((int)ExitCode.SolutionOrProjectFileParameterMissing);
            }

            if (string.IsNullOrEmpty(outputDirectory))
            {
                Console.Error.WriteLine($"The output directory is required");
                return((int)ExitCode.OutputDirectoryParameterMissing);
            }

            if ((string.IsNullOrEmpty(githubUsername) ^ string.IsNullOrEmpty(githubToken)) ||
                (string.IsNullOrEmpty(githubUsernameDeprecated) ^ string.IsNullOrEmpty(githubTokenDeprecated)))
            {
                Console.Error.WriteLine($"Both GitHub username and token are required");
                return((int)ExitCode.GitHubParameterMissing);
            }

            dotnetCommandService.TimeoutMilliseconds = dotnetCommandTimeout;
            projectFileService.DisablePackageRestore = disablePackageRestore;

            // retrieve nuget package cache paths
            var packageCachePathsResult = dotnetUtilsService.GetPackageCachePaths();

            if (!packageCachePathsResult.Success)
            {
                Console.Error.WriteLine("Unable to find local package cache locations...");
                Console.Error.WriteLine(packageCachePathsResult.ErrorMessage);
                return((int)ExitCode.LocalPackageCacheError);
            }

            Console.WriteLine("Found the following local nuget package cache locations:");
            foreach (var path in packageCachePathsResult.Result)
            {
                Console.WriteLine($"    {path}");
            }

            // instantiate services

            var           fileDiscoveryService = new FileDiscoveryService(Program.fileSystem);
            GithubService githubService        = null;

            if (!(disableGithubLicenses || disableGithubLicensesDeprecated))
            {
                // GitHubService requires its own HttpClient as it adds a default authorization header
                if (!string.IsNullOrEmpty(githubBearerToken))
                {
                    githubService = new GithubService(new HttpClient(), githubBearerToken);
                }
                else if (!string.IsNullOrEmpty(githubBearerTokenDeprecated))
                {
                    githubService = new GithubService(new HttpClient(), githubBearerTokenDeprecated);
                }
                else if (!string.IsNullOrEmpty(githubUsername))
                {
                    githubService = new GithubService(new HttpClient(), githubUsername, githubToken);
                }
                else if (!string.IsNullOrEmpty(githubUsernameDeprecated))
                {
                    githubService = new GithubService(new HttpClient(), githubUsernameDeprecated, githubTokenDeprecated);
                }
                else
                {
                    githubService = new GithubService(new HttpClient());
                }
            }
            var nugetService = new NugetService(
                Program.fileSystem,
                packageCachePathsResult.Result,
                githubService,
                Program.httpClient,
                baseUrl,
                disableHashComputation);

            var packages = new HashSet <NugetPackage>();

            // determine what we are analyzing and do the analysis
            var fullSolutionOrProjectFilePath = Program.fileSystem.Path.GetFullPath(SolutionOrProjectFile);

            var topLevelComponent = new Component
            {
                // name is set below
                Version = string.IsNullOrEmpty(setVersion) ? "0.0.0" : setVersion,
                Type    = setType == Component.Classification.Null ? Component.Classification.Application : setType,
            };

            try
            {
                if (SolutionOrProjectFile.ToLowerInvariant().EndsWith(".sln", StringComparison.OrdinalIgnoreCase))
                {
                    packages = await solutionFileService.GetSolutionNugetPackages(fullSolutionOrProjectFilePath, baseIntermediateOutputPath, excludetestprojects).ConfigureAwait(false);

                    topLevelComponent.Name = fileSystem.Path.GetFileNameWithoutExtension(SolutionOrProjectFile);
                }
                else if (Utils.IsSupportedProjectType(SolutionOrProjectFile) && scanProjectReferences)
                {
                    packages = await projectFileService.RecursivelyGetProjectNugetPackagesAsync(fullSolutionOrProjectFilePath, baseIntermediateOutputPath, excludetestprojects).ConfigureAwait(false);

                    topLevelComponent.Name = fileSystem.Path.GetFileNameWithoutExtension(SolutionOrProjectFile);
                }
                else if (Utils.IsSupportedProjectType(SolutionOrProjectFile))
                {
                    packages = await projectFileService.GetProjectNugetPackagesAsync(fullSolutionOrProjectFilePath, baseIntermediateOutputPath, excludetestprojects).ConfigureAwait(false);

                    topLevelComponent.Name = fileSystem.Path.GetFileNameWithoutExtension(SolutionOrProjectFile);
                }
                else if (Program.fileSystem.Path.GetFileName(SolutionOrProjectFile).ToLowerInvariant().Equals("packages.config", StringComparison.OrdinalIgnoreCase))
                {
                    packages = await packagesFileService.GetNugetPackagesAsync(fullSolutionOrProjectFilePath).ConfigureAwait(false);

                    topLevelComponent.Name = fileSystem.Path.GetDirectoryName(fullSolutionOrProjectFilePath);
                }
                else if (fileSystem.Directory.Exists(fullSolutionOrProjectFilePath))
                {
                    packages = await packagesFileService.RecursivelyGetNugetPackagesAsync(fullSolutionOrProjectFilePath).ConfigureAwait(false);

                    topLevelComponent.Name = fileSystem.Path.GetDirectoryName(fullSolutionOrProjectFilePath);
                }
                else
                {
                    Console.Error.WriteLine($"Only .sln, .csproj, .vbproj, and packages.config files are supported");
                    return((int)ExitCode.InvalidOptions);
                }
            }
            catch (DotnetRestoreException)
            {
                return((int)ExitCode.DotnetRestoreFailed);
            }

            if (!string.IsNullOrEmpty(setName))
            {
                topLevelComponent.Name = setName;
            }

            // get all the components and depdency graph from the NuGet packages
            var components         = new HashSet <Component>();
            var dependencies       = new List <Dependency>();
            var directDependencies = new Dependency {
                Dependencies = new List <Dependency>()
            };
            var transitiveDepencies = new HashSet <string>();

            try
            {
                var bomRefLookup = new Dictionary <(string, string), string>();
                foreach (var package in packages)
                {
                    var component = await nugetService.GetComponentAsync(package).ConfigureAwait(false);

                    if (component != null &&
                        (component.Scope != Component.ComponentScope.Excluded || !excludeDev)
                        )
                    {
                        components.Add(component);
                    }
                    bomRefLookup[(component.Name.ToLower(CultureInfo.InvariantCulture), (component.Version.ToLower(CultureInfo.InvariantCulture)))] = component.BomRef;
Ejemplo n.º 3
0
        async Task <int> OnExecuteAsync()
        {
            Console.WriteLine();

            // check parameter values
            if (string.IsNullOrEmpty(SolutionOrProjectFile))
            {
                Console.Error.WriteLine($"A path is required");
                return((int)ExitCode.SolutionOrProjectFileParameterMissing);
            }

            if (string.IsNullOrEmpty(outputDirectory))
            {
                Console.Error.WriteLine($"The output directory is required");
                return((int)ExitCode.OutputDirectoryParameterMissing);
            }

            if ((string.IsNullOrEmpty(githubUsername) ^ string.IsNullOrEmpty(githubToken)) ||
                (string.IsNullOrEmpty(githubUsernameDeprecated) ^ string.IsNullOrEmpty(githubTokenDeprecated)))
            {
                Console.Error.WriteLine($"Both GitHub username and token are required");
                return((int)ExitCode.GitHubParameterMissing);
            }

            dotnetCommandService.TimeoutMilliseconds = dotnetCommandTimeout;

            // retrieve nuget package cache paths
            var packageCachePathsResult = dotnetUtilsService.GetPackageCachePaths();

            if (!packageCachePathsResult.Success)
            {
                Console.Error.WriteLine("Unable to find local package cache locations...");
                Console.Error.WriteLine(packageCachePathsResult.ErrorMessage);
                return((int)ExitCode.LocalPackageCacheError);
            }

            Console.WriteLine("Found the following local nuget package cache locations:");
            foreach (var path in packageCachePathsResult.Result)
            {
                Console.WriteLine($"    {path}");
            }

            // instantiate services

            var           fileDiscoveryService = new FileDiscoveryService(Program.fileSystem);
            GithubService githubService        = null;

            if (!(disableGithubLicenses || disableGithubLicensesDeprecated))
            {
                // GitHubService requires its own HttpClient as it adds a default authorization header
                if (!string.IsNullOrEmpty(githubBearerToken))
                {
                    githubService = new GithubService(new HttpClient(), githubBearerToken);
                }
                else if (!string.IsNullOrEmpty(githubBearerTokenDeprecated))
                {
                    githubService = new GithubService(new HttpClient(), githubBearerTokenDeprecated);
                }
                else if (!string.IsNullOrEmpty(githubUsername))
                {
                    githubService = new GithubService(new HttpClient(), githubUsername, githubToken);
                }
                else if (!string.IsNullOrEmpty(githubUsernameDeprecated))
                {
                    githubService = new GithubService(new HttpClient(), githubUsernameDeprecated, githubTokenDeprecated);
                }
                else
                {
                    githubService = new GithubService(new HttpClient());
                }
            }
            var nugetService = new NugetService(
                Program.fileSystem,
                packageCachePathsResult.Result,
                githubService,
                Program.httpClient,
                baseUrl);

            var packages = new HashSet <NugetPackage>();

            // determine what we are analyzing and do the analysis
            var fullSolutionOrProjectFilePath = Program.fileSystem.Path.GetFullPath(SolutionOrProjectFile);
            var attr = Program.fileSystem.File.GetAttributes(fullSolutionOrProjectFilePath);

            try
            {
                if (SolutionOrProjectFile.ToLowerInvariant().EndsWith(".sln", StringComparison.OrdinalIgnoreCase))
                {
                    packages = await solutionFileService.GetSolutionNugetPackages(fullSolutionOrProjectFilePath).ConfigureAwait(false);
                }
                else if (Core.Utils.IsSupportedProjectType(SolutionOrProjectFile) && scanProjectReferences)
                {
                    packages = await projectFileService.RecursivelyGetProjectNugetPackagesAsync(fullSolutionOrProjectFilePath).ConfigureAwait(false);
                }
                else if (Core.Utils.IsSupportedProjectType(SolutionOrProjectFile))
                {
                    packages = await projectFileService.GetProjectNugetPackagesAsync(fullSolutionOrProjectFilePath).ConfigureAwait(false);
                }
                else if (Program.fileSystem.Path.GetFileName(SolutionOrProjectFile).ToLowerInvariant().Equals("packages.config", StringComparison.OrdinalIgnoreCase))
                {
                    packages = await packagesFileService.GetNugetPackagesAsync(fullSolutionOrProjectFilePath).ConfigureAwait(false);
                }
                else if (attr.HasFlag(FileAttributes.Directory))
                {
                    packages = await packagesFileService.RecursivelyGetNugetPackagesAsync(fullSolutionOrProjectFilePath).ConfigureAwait(false);
                }
                else
                {
                    Console.Error.WriteLine($"Only .sln, .csproj, .vbproj, and packages.config files are supported");
                    return((int)ExitCode.InvalidOptions);
                }
            }
            catch (DotnetRestoreException)
            {
                return((int)ExitCode.DotnetRestoreFailed);
            }

            // get all the components from the NuGet packages
            var components = new HashSet <Component>();

            try
            {
                foreach (var package in packages)
                {
                    var component = await nugetService.GetComponentAsync(package).ConfigureAwait(false);

                    if (component != null &&
                        (component.Scope != "excluded" || !excludeDev)
                        )
                    {
                        components.Add(component);
                    }
                }
            }
            catch (InvalidGitHubApiCredentialsException)
            {
                return((int)ExitCode.InvalidGitHubApiCredentials);
            }
            catch (GitHubApiRateLimitExceededException)
            {
                return((int)ExitCode.GitHubApiRateLimitExceeded);
            }
            catch (GitHubLicenseResolutionException)
            {
                return((int)ExitCode.GitHubLicenseResolutionFailed);
            }

            // create the BOM
            Console.WriteLine();
            Console.WriteLine("Creating CycloneDX BOM");
            var bom = new Bom();

            if (!(noSerialNumber || noSerialNumberDeprecated))
            {
                bom.SerialNumber = "urn:uuid:" + System.Guid.NewGuid().ToString();
            }
            bom.Components = components;

            var bomContents = BomService.CreateDocument(bom, json);

            // check if the output directory exists and create it if needed
            var bomPath = Program.fileSystem.Path.GetFullPath(outputDirectory);

            if (!Program.fileSystem.Directory.Exists(bomPath))
            {
                Program.fileSystem.Directory.CreateDirectory(bomPath);
            }

            // write the BOM to disk
            var bomFilename = Program.fileSystem.Path.Combine(bomPath, json ? "bom.json" : "bom.xml");

            Console.WriteLine("Writing to: " + bomFilename);
            Program.fileSystem.File.WriteAllText(bomFilename, bomContents);

            return(0);
        }