C#
This article shows you how to analyze your applications written in C# using preZero. It assumes that you have already set up and authenticated with Qwiet.
Requirements
See Prerequisites for more information.
Preparing your application for analysis
Before analyzing your code with preZero, we recommend either:
- Restoring the dependencies of your application;
- Building your application (since this will implicitly restore your application's dependencies and produce additional artifacts that may be useful for analysis).
.NET application
You can restore and build a .NET application as follows:
Launch a command prompt
Navigate to your project location
Restore NuGet packages by running
dotnet restore <MySolution.sln>
Start the build by running
dotnet build --no-restore <MySolution.sln>
.NET Framework application
You can restore and build a .NET Framework application with the following:
Launch the Developer Command Prompt for Visual Studio
Navigate to your project location
Restore NuGet packages by running
nuget.exe restore <MySolution.sln>
Start the build by running
msbuild <MySolution.sln>
Analyzing your C# application
Qwiet offers a sample application that you can use to run and test preZero. It also includes a functioning configuration file to demonstrate how you can leverage Azure Pipelines or GitHub Actions to automate code analysis whenever you open a new Pull Request (PR).
To analyze your C# application, run:
# Ensure your application dependencies are restored
sl.exe analyze --app <name> --csharp [<path>]
Non-Windows users should invoke the Qwiet CLI using
sl
instead ofsl.exe
.
Parameter | Description |
---|---|
--app <name> | The name of the application to be analyzed (maximum length: 100 characters) |
--csharp | The flag identifying the application's language |
<path> | The location of the application's .csproj or .sln file to be analyzed |
See the CLI reference for additional sl.exe analyze
options.
SCA
To identify open-source vulnerabilities, Qwiet preZero automatically searches for build manifests in the project path you provided when running sl.exe analyze
. However, depending on how your project repo is structured, you may need to provide --oss-project-dir <project-path>
so that Qwiet preZero can identify your dependencies.
Tagging results with your branch name
To include the branch name in your preZero results, allowing you to distinguish one set of results from another, add the following to your invocation of Qwiet:
sl.exe analyze --tag branch=`git symbolic-ref --short HEAD`
If you're working in a GitHub environment (e.g., GitHub Actions), you can also use --tag branch=${{ github.head_ref }}
to populate your branch name.
If you don't provide a branch name, but Qwiet detects one available in your environment, it will use that name.
Enabling log information
By default, we print logs at the Information level. If you would like more detailed information, pass in the --verbose
flag:
sl.exe analyze --csharp --verbose --app Xyz app.csproj
You can find the logs generated by Qwiet in the Windows temp directory.
Troubleshooting
If you have any issues scanning your project, please see our general troubleshooting page, as well as our C#-specific suggestions that follow.
Artifact and dll not found errors
If you see the errors that look like this:
fail: Buildalyzer.Logging.EventProcessor[0]
System.IO.FileNotFoundException: Could not find file '/Users/prabhu/Downloads/EU-OutageStatusQuery/AzureFunctions/OutageStatusFunctions/OmsData.Peco/bin/Debug/netcoreapp3.1/bin/OmsData.Peco.dll'.
File name: '/Users/prabhu/Downloads/EU-OutageStatusQuery/AzureFunctions/OutageStatusFunctions/OmsData.Peco/bin/Debug/netcoreapp3.1/bin/OmsData.Peco.dll'
at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirectory, Func`2 errorRewriter)
at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String path, OpenFlags flags, Int32 mode)
at System.IO.FileStream.OpenHandle(FileMode mode, FileShare share, FileOptions options)
Or this:
fail[39m[22m[49m: Buildalyzer.Logging.EventProcessor[0]
2021-02-03T18:39:57.5318095Z Metadata file '/src/src/app/Fool.Marthetron.Shared/bin/Release/netstandard2.1/Fool.Marthetron.Shared.dll' could not be found
This means that you must pass additional build parameters to sl.exe analyze
to ensure that the dependent projects can be built successfully. Typically, the developer should be able to provide the necessary build parameters, but we've found the following five flags to be helpful:
sl.exe analyze --app app-name /
--verbose /
--csharp /
"sln file name" /
-- /p:BuildProjectReferences="true" /
/p:SkipCompilerExecution="false" /
/p:CopyBuildOutputToOutputDirectory="true" /
/p:CopyOutputSymbolsToOutputDirectory="true" /
/p:SkipCopyBuildProduct="false"
If the project fails to rebuild after three attempts, even with the addition of build flags, please contact Support for further assistance.
Combining C# projects for analysis
When working with .NET apps, you can combine multiple C# projects for analysis as follows:
sl.exe analyze --app Xyz --csharp --dep lib.csproj --dep component.csproj app.csproj
Note that you can include --dep
multiple times for libs, subprojects, components, etc. The --dep
option allows you to filter the subprojects/dependencies to include with the primary .csproj
project for analysis. This allows you to adopt the middle ground between analyzing just the primary project:
sl.exe analyze --app Xyz --csharp app.csproj
and analyzing the primary file with all of its dependencies/subprojects:
sl.exe analyze --app Xyz --csharp <path-to-project-file>
Recursively finding and scanning your solution/project files
The following example shows you how to modify the sl.exe analyze
invocation to recursively find all .sln
files and scan them with Qwiet:
# Recursively find all .sln files and scan them with Qwiet preZero
# Be sure to change the app.group value from "test-appgroup" to your preferred name
Get-ChildItem -Path . -Filter *.sln -Recurse -ErrorAction SilentlyContinue -Force | ForEach-Object {
sl.exe analyze --csharp --oss-project-dir $($_.Directory) --tag app.group=test-appgroup --app $($_.Name -replace '.sln', '') $($_.FullName)
}
Alternatively, you can recursively find and scan all .csproj files if .sln
-based scans are taking too long:
# Recursively find all .csproj files and scan them with Qwiet preZero
# Use this when .sln based scans are taking too long
# Be sure to change the app.group value from ß"test-appgroup" to your preferred name
Get-ChildItem -Path . -Filter *.csproj -Recurse -ErrorAction SilentlyContinue -Force | ForEach-Object {
sl.exe analyze --csharp --oss-project-dir $($_.Directory) --tag app.group=test-appgroup --app $($_.Name -replace '.csproj', '') $($_.FullName)
}
Apps utilizing MSBuild project files
If your primary application refers to dependencies (e.g., dll
files), Qwiet's default code analysis mode will not look into the dependency files. However, if the csproj
files with source code for dependencies are available, you can modify the parameters passed to sl.exe analyze
to ensure that Qwiet analyzes all relevant dependencies.
In short, Qwiet can look at dependencies and dependencies of dependencies (which we call a transitive dependency) during the code analysis process.
To scan your primary solution and its dependencies, include the following flag after initial double ellipsis: --msbuild-proj <path-to-proj-file>
. Note that a project file ends with the .proj
suffix.
For example:
sl.exe analyze --app yourApp --csharp <path-to-sln-or-csproj> -- --msbuild-proj <path-to-proj-file>
However, if your solution refers to dependencies that, in turn, rely on dependencies, you can indicate to Qwiet that you would like such dependencies included in the analysis. Including the flag --msbuild-proj-iter <integer>
allows you to provide the integer specifying the levels of transitive dependencies you want to be included in your scan.
For example, let's say that your sl.exe analyze
command is as follows:
sl.exe analyze --app yourApp --csharp <path-to-sln-or-csproj> -- --msbuild-proj <path-to-proj-file> --msbuild-proj-iter 2
Qwiet will look at your primary project file, any direct dependencies, and any dependencies of direct dependencies. Qwiet will ignore any further references.
Example usage
Let's say that you have TheApp, which is structured as follows:
├── TheApp
│ └── TheApp.csproj
├── TheLib
| └── TheLib.csproj
├── AnotherLib
│ └── AnotherLib
│ └── AnotherLib
│ └── AnotherLib.csproj
├── CoolClassLib
│ └── CoolClassLib
│ └── CoolClassLib
│ └── CoolClassLib.csproj
├── NotUsedLib
└── NotUsedLib
└── NotUsedLib
└── NotUsedLib.csproj
The app's .sln
file only mentions the TheApp.csproj
:
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.810.8
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TheApp", "TheApp\TheApp.csproj", "{E776BD21-3B47-4184-93B7-7DA198474F1E}"
EndProject
...
TheApp.csproj
references its dependencies through a <Reference>
item, instead of a <ProjectReference>
item (that is, it references .dll
files). Its direct dependencies are TheLib
and AnotherLib
:
<Project Sdk="Microsoft.NET.Sdk.Web">
…
<ItemGroup>
<Reference Include="TheLib">
<HintPath>..\TheLib.dll</HintPath>
</Reference>
<Reference Include="AnotherLib">
<HintPath>..\AnotherLib.dll</HintPath>
</Reference>
</ItemGroup>
</Project>
However, AnotherLib references CoolClassLib, making CoolClassLib a transitive dependency of TheApp:
<Project Sdk="Microsoft.NET.Sdk">
…
<ItemGroup>
<None Remove="CoolClassLib" />
</ItemGroup>
<ItemGroup>
<Reference Include="CoolClassLib">
<HintPath>..\..\..\CoolClassLib.dll</HintPath>
</Reference>
</ItemGroup>
</Project>
To ensure that Qwiet looks into all of TheApp's dependencies, you must have an MSBuild project file (this is a build specification for all such dependencies). The following is a sample project file called TheAppFullBuild.proj
:
<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
…
<Target Name="Assemblies">
<MSBuild Properties="… Projects="
<path-to>/TheApp/TheLib/TheLib.csproj;
<path-to>/TheApp/AnotherLib/AnotherLib/AnotherLib/AnotherLib.csproj;
<path-to>/TheApp/CoolClassLib/CoolClassLib/CoolClassLib/CoolClassLib.csproj;
<path-to>/TheApp/NotUsedLib/NotUsedLib/NotUsedLib/NotUsedLib.csproj;
"/>
</Target>
</Project>
Therefore, the sl.exe analyze
command to scan TheApp is:
sl.exe analyze --app TheApp --csharp TheApp.sln -- --msbuild-proj TheAppFullBuild.proj --msbuild-proj-iter 2
Improving performance by omitting Razor files from the scan
By default, preZero looks for and scans Razor files included in your project. If you would like to disable this functionality to improve performance, you can pass in --disable-razor
after a double ellipsis:
sl.exe analyze --app yourApp --csharp <path-to-sln-or-csproj> -- --disable-razor
Deprecated flags
The --dotnet
, --dotnet-core
, and --dotnet-framework
flags have been deprecated, since Qwiet AI will automatically select the best option for the application. However, Qwiet AI is backward compatible, so including one of these flags will present no problem. Additionally, if you observe any issues, you may specify the flag that best fits the needs of your application to see if that improves your results.