-
Notifications
You must be signed in to change notification settings - Fork 0
Integrate run command #64
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- Updated package versions in CrossRepoActions.csproj for ktsu libraries and Microsoft packages. - Added support for central package management in Dotnet class, including methods to check for central management, update packages, and handle outdated dependencies. - Refactored UpdatePackages verb to accommodate both central and traditional package management approaches.
- Introduced comprehensive documentation outlining the features, installation instructions, usage examples, and command options for the CrossRepoActions .NET console application. - Highlighted core commands such as UpdatePackages, BuildAndTest, and GitPull, along with their functionalities. - Included prerequisites, configuration options, and dependencies to assist users in setting up and utilizing the application effectively.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Git Class Vulnerable to Command Injection
The Git class methods using RunCommand.Execute are vulnerable to command injection and failures. Parameters such as commit messages, file paths, and repository paths are directly interpolated into the shell command string without proper quoting or escaping. This allows shell metacharacters (e.g., spaces, quotes, semicolons, pipes) to break commands or execute arbitrary code. This regression occurred when switching from PowerShell's safe parameter handling to direct string interpolation.
CrossRepoActions/Git.cs#L35-L81
CrossRepoActions/CrossRepoActions/Git.cs
Lines 35 to 81 in 5da8870
| RunCommand.Execute($"git -C {repo} pull --all -v", new LineOutputHandler(s => results.Add(s.Trim()), s => results.Add(s.Trim()))); | |
| return results; | |
| } | |
| internal static IEnumerable<string> Push(AbsoluteDirectoryPath repo) | |
| { | |
| Collection<string> results = []; | |
| RunCommand.Execute($"git -C {repo} push -v", new LineOutputHandler(s => results.Add(s.Trim()), s => results.Add(s.Trim()))); | |
| return results; | |
| } | |
| internal static IEnumerable<string> Status(AbsoluteDirectoryPath repo, AbsoluteFilePath filePath) | |
| { | |
| Collection<string> results = []; | |
| RunCommand.Execute($"git -C {repo} status --short -- {filePath}", new LineOutputHandler(s => results.Add(s.Trim()), s => results.Add(s.Trim()))); | |
| return results; | |
| } | |
| internal static IEnumerable<string> Unstage(AbsoluteDirectoryPath repo) | |
| { | |
| Collection<string> results = []; | |
| RunCommand.Execute($"git -C {repo} restore --staged {repo}", new LineOutputHandler(s => results.Add(s.Trim()), s => results.Add(s.Trim()))); | |
| return results; | |
| } | |
| internal static IEnumerable<string> Add(AbsoluteDirectoryPath repo, AbsoluteFilePath filePath) | |
| { | |
| Collection<string> results = []; | |
| RunCommand.Execute($"git -C {repo} add {filePath}", new LineOutputHandler(s => results.Add(s.Trim()), s => results.Add(s.Trim()))); | |
| return results; | |
| } | |
| internal static IEnumerable<string> Commit(AbsoluteDirectoryPath repo, string message) | |
| { | |
| Collection<string> results = []; | |
| RunCommand.Execute($"git -C {repo} commit -m {message}", new LineOutputHandler(s => results.Add(s.Trim()), s => results.Add(s.Trim()))); |
Bug: Path Quoting and Test Output Issues
Multiple dotnet commands executed via RunCommand.Execute use unquoted project or solution file paths in their command strings. This causes commands to fail if paths contain spaces, as RunCommand does not automatically handle quoting like the previous PowerShell implementation. Affected methods include BuildProject, GetProjects, GetSolutionDependencies, GetOutdatedProjectDependencies, UpdatePackagesTraditional, GetProjectAssemblyName, GetProjectVersion, IsProjectPackable, GetOutdatedCentralPackageDependencies, and GetOutdatedPackagesJson.
Additionally, the RunTests() method now incorrectly filters its output to only error messages by calling GetErrors(), which breaks downstream logic expecting full test output to parse pass/fail results.
CrossRepoActions/Dotnet.cs#L31-L173
CrossRepoActions/CrossRepoActions/Dotnet.cs
Lines 31 to 173 in 5da8870
| RunCommand.Execute($"dotnet build --nologo {projectFile}", new LineOutputHandler(results.Add, results.Add)); | |
| return GetErrors(results); | |
| } | |
| internal static Collection<string> RunTests() | |
| { | |
| Collection<string> results = []; | |
| RunCommand.Execute($"dotnet vstest **/bin/**/*Test.dll --logger:console;verbosity=normal --nologo", new LineOutputHandler(results.Add, results.Add)); | |
| return GetErrors(results); | |
| } | |
| internal static Collection<string> GetTests() | |
| { | |
| Collection<string> results = []; | |
| RunCommand.Execute($"dotnet vstest --ListTests --nologo **/bin/**/*Test.dll", new LineOutputHandler(results.Add, results.Add)); | |
| var filteredResults = results | |
| .Where(r => r is not null && !r.StartsWith("The following") && !r.StartsWith("No test source")) | |
| .ToCollection(); | |
| return filteredResults; | |
| } | |
| internal static Collection<string> GetProjects(AbsoluteFilePath solutionFile) | |
| { | |
| Collection<string> results = []; | |
| RunCommand.Execute($"dotnet sln {solutionFile} list", new LineOutputHandler(results.Add, results.Add)); | |
| var filteredResults = results | |
| .Where(r => r is not null && r.EndsWithOrdinal(".csproj")) | |
| .ToCollection(); | |
| return filteredResults; | |
| } | |
| internal static Collection<Package> GetSolutionDependencies(AbsoluteFilePath solutionFile) | |
| { | |
| Collection<string> results = []; | |
| RunCommand.Execute($"dotnet list {solutionFile} package --include-transitive", new LineOutputHandler(results.Add, results.Add)); | |
| var filteredResults = results | |
| .Where(r => r is not null && r.StartsWithOrdinal(">")) | |
| .ToCollection(); | |
| var dependencies = filteredResults | |
| .Select(r => | |
| { | |
| string[] parts = r.Split(' '); | |
| return new Package() | |
| { | |
| Name = parts[1], | |
| Version = parts.Last(), | |
| }; | |
| }) | |
| .ToCollection(); | |
| return dependencies; | |
| } | |
| private const string packageJsonError = "Could not parse JSON output from 'dotnet list package --format-json'"; | |
| internal static Collection<Package> GetOutdatedProjectDependencies(AbsoluteFilePath projectFile) | |
| { | |
| Collection<string> results = []; | |
| RunCommand.Execute($"dotnet list {projectFile} package --format=json", new LineOutputHandler(results.Add, results.Add)); | |
| string jsonString = string.Join("", results); | |
| var rootObject = JsonNode.Parse(jsonString)?.AsObject() | |
| ?? throw new InvalidDataException(packageJsonError); | |
| var projects = rootObject["projects"]?.AsArray() | |
| ?? throw new InvalidDataException(packageJsonError); | |
| var frameworks = projects.Where(p => | |
| { | |
| var pObj = p?.AsObject(); | |
| return pObj?["frameworks"]?.AsArray() != null; | |
| }) | |
| .SelectMany(p => | |
| { | |
| return p?.AsObject()?["frameworks"]?.AsArray() | |
| ?? throw new InvalidDataException(packageJsonError); | |
| }); | |
| var packages = frameworks.SelectMany(f => | |
| { | |
| return (f as JsonObject)?["topLevelPackages"]?.AsArray() | |
| ?? throw new InvalidDataException(packageJsonError); | |
| }) | |
| .Select(ExtractPackageFromJsonNode) | |
| .DistinctBy(p => p.Name) | |
| .ToCollection(); | |
| return packages; | |
| } | |
| private static Package ExtractPackageFromJsonNode(JsonNode? p) | |
| { | |
| string name = p?["id"]?.AsValue().GetValue<string>() | |
| ?? throw new InvalidDataException(packageJsonError); | |
| string version = p?["requestedVersion"]?.AsValue().GetValue<string>() | |
| ?? throw new InvalidDataException(packageJsonError); | |
| return new Package() | |
| { | |
| Name = name, | |
| Version = version, | |
| }; | |
| } | |
| internal static Collection<string> UpdatePackages(AbsoluteFilePath projectFile, IEnumerable<Package> packages) | |
| { | |
| // Find the solution file to determine if central package management is used | |
| var solutionPath = FindSolutionForProject(projectFile); | |
| if (solutionPath != null && UsesCentralPackageManagement(solutionPath)) | |
| { | |
| // Use central package management update approach | |
| return UpdatePackagesWithCentralManagement(solutionPath, packages); | |
| } | |
| // Use traditional per-project update approach | |
| return UpdatePackagesTraditional(projectFile, packages); | |
| } | |
| /// <summary> | |
| /// Updates packages using traditional per-project approach. | |
| /// </summary> | |
| private static Collection<string> UpdatePackagesTraditional(AbsoluteFilePath projectFile, IEnumerable<Package> packages) | |
| { | |
| Collection<string> output = []; | |
| foreach (var package in packages) | |
| { | |
| Collection<string> results = []; | |
| string pre = package.Version.Contains('-') ? "--prerelease" : ""; | |
| RunCommand.Execute($"dotnet add {projectFile} package {package.Name} {pre}", new LineOutputHandler(results.Add, results.Add)); |
Bug: Unquoted Paths and Names Cause Command Failures
The dotnet add command is constructed using unquoted string interpolation for the project file path and package name. This leads to command execution failures if paths or package names contain spaces, and introduces a command injection vulnerability if package names contain shell metacharacters.
CrossRepoActions/Dotnet.cs#L172-L173
CrossRepoActions/CrossRepoActions/Dotnet.cs
Lines 172 to 173 in 5da8870
| string pre = package.Version.Contains('-') ? "--prerelease" : ""; | |
| RunCommand.Execute($"dotnet add {projectFile} package {package.Name} {pre}", new LineOutputHandler(results.Add, results.Add)); |
Bug: Missing Flag Causes Incorrect Package Listing
The GetOutdatedProjectDependencies method is missing the --outdated flag in its dotnet list package command. This causes the method to return all packages for a project instead of only the outdated ones, contrary to its intended purpose.
CrossRepoActions/Dotnet.cs#L101-L102
CrossRepoActions/CrossRepoActions/Dotnet.cs
Lines 101 to 102 in 5da8870
| RunCommand.Execute($"dotnet list {projectFile} package --format=json", new LineOutputHandler(results.Add, results.Add)); |
Was this report helpful? Give feedback by reacting with 👍 or 👎
No description provided.