diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
new file mode 100644
index 0000000..831d039
--- /dev/null
+++ b/.config/dotnet-tools.json
@@ -0,0 +1,12 @@
+{
+ "version": 1,
+ "isRoot": true,
+ "tools": {
+ "cake.tool": {
+ "version": "3.0.0",
+ "commands": [
+ "dotnet-cake"
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..0f1fbf3
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1 @@
+* @louisfischer
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..ac6621f
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,11 @@
+# To get started with Dependabot version updates, you'll need to specify which
+# package ecosystems to update and where the package manifests are located.
+# Please see the documentation for all configuration options:
+# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
+
+version: 2
+updates:
+ - package-ecosystem: "" # See documentation for possible values
+ directory: "/" # Location of package manifests
+ schedule:
+ interval: "weekly"
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..eac08f5
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,78 @@
+name: Build
+
+on:
+ pull_request:
+ workflow_dispatch:
+ inputs:
+ target:
+ description: 'Task'
+ required: true
+ default: Default
+ type: choice
+ options:
+ - Default
+ - Clean
+ - Restore
+ - Build
+ - Pack
+ - Push
+
+ pushToNuget:
+ description: 'Push to Nuget'
+ required: false
+ default: false
+ type: boolean
+
+ logLevel:
+ description: 'Verbosity'
+ required: false
+ default: Normal
+ type: choice
+ options:
+ - Quiet
+ - Minimal
+ - Normal
+ - Verbose
+ - Diagnostic
+ push:
+ branches:
+ - "**"
+ tags:
+ - "*.*.*"
+ paths-ignore:
+ - "README.md"
+
+env:
+ DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
+ DOTNET_CLI_TELEMETRY_OPTOUT: true
+ DOTNET_NOLOGO: true
+
+jobs:
+ build:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ os: [ubuntu-latest]
+
+ name: ${{ matrix.os }}
+ steps:
+ - name: Setup net6.0
+ uses: actions/setup-dotnet@v3.0.3
+ with:
+ dotnet-version: 6.x
+
+ - name: Checkout
+ uses: actions/checkout@v3.5.2
+ with:
+ fetch-depth: 0
+
+ - name: Run the Cake script
+ uses: cake-build/cake-action@master
+ with:
+ target: ${{ inputs.target || 'Default' }}
+ verbosity: ${{ inputs.logLevel || 'Diagnostic' }}
+ cake-version: tool-manifest
+ arguments: |
+ NUGET_PUSH: ${{ inputs.pushToNuget || true }}
+ NUGET_URL: ${{ secrets.NUGET_SOURCE }}
+ NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
new file mode 100644
index 0000000..26a06b6
--- /dev/null
+++ b/.github/workflows/codeql.yml
@@ -0,0 +1,40 @@
+name: CodeQL
+
+on:
+ push:
+ branches: [ "main" ]
+ pull_request:
+ branches: [ "main" ]
+ schedule:
+ - cron: '44 6 * * 6'
+
+jobs:
+ analyze:
+ name: Analyze
+ runs-on: ubuntu-latest
+ permissions:
+ actions: read
+ contents: read
+ security-events: write
+
+ strategy:
+ fail-fast: false
+ matrix:
+ language: [ 'csharp' ]
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v2
+ with:
+ languages: ${{ matrix.language }}
+ queries: security-extended,security-and-quality
+
+ - name: Autobuild
+ uses: github/codeql-action/autobuild@v2
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v2
+ with:
+ category: "/language:${{matrix.language}}"
diff --git a/.gitignore b/.gitignore
index a9e78cf..bf11f41 100644
--- a/.gitignore
+++ b/.gitignore
@@ -276,4 +276,5 @@ __pycache__/
# Cake - Uncomment if you are using it
tools/**
!tools/packages.config
-BuildArtifacts/
\ No newline at end of file
+BuildArtifacts/
+.cake/
diff --git a/Cake.CodeQL.Cli.sln b/Cake.CodeQL.Cli.sln
index c43c4dd..03a08f9 100644
--- a/Cake.CodeQL.Cli.sln
+++ b/Cake.CodeQL.Cli.sln
@@ -5,6 +5,15 @@ VisualStudioVersion = 17.3.32819.101
MinimumVisualStudioVersion = 15.0.26124.0
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cake.CodeQL.Cli", "src\Cake.CodeQL.Cli\Cake.CodeQL.Cli.csproj", "{32D1A768-6DDF-4127-967D-DA9BD00C8F26}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{46391845-2542-4C09-B354-DFB023C6FB4E}"
+ ProjectSection(SolutionItems) = preProject
+ build.cake = build.cake
+ .github\workflows\build.yml = .github\workflows\build.yml
+ cake.config = cake.config
+ .github\workflows\codeql.yml = .github\workflows\codeql.yml
+ .config\dotnet-tools.json = .config\dotnet-tools.json
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
diff --git a/README.md b/README.md
index 1a4f0bd..8957d03 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ This plugin is a set of Cake aliases for [GitHub CodeQL CLI](https://docs.github
```
### Cake Frosting Project
```xml
-
+
```
## Discussion
diff --git a/build.cake b/build.cake
new file mode 100644
index 0000000..0aa063b
--- /dev/null
+++ b/build.cake
@@ -0,0 +1,105 @@
+#tool "dotnet:?package=minver-cli&version=4.2.0"
+#addin "nuget:?package=Cake.MinVer&version=3.0.0"
+#addin "nuget:?package=Cake.Args&version=3.0.0"
+
+var target = ArgumentOrDefault("Target") ?? "Default";
+var buildVersion = MinVer(s => s.WithTagPrefix("v").WithDefaultPreReleasePhase("preview"));
+
+Task("Clean")
+ .Does(() =>
+{
+ EnsureDirectoryDoesNotExist("./artifact/");
+ CleanDirectories("./**/^{bin,obj}");
+});
+
+Task("Restore")
+ .IsDependentOn("Clean")
+ .Does(() =>
+{
+ DotNetRestore("./Cake.CodeQL.Cli.sln", new DotNetRestoreSettings
+ {
+ LockedMode = true,
+ });
+});
+
+Task("Build")
+ .IsDependentOn("Restore")
+ .DoesForEach(new[] { "Debug", "Release" }, (configuration) =>
+{
+ DotNetBuild("./Cake.CodeQL.Cli.sln", new DotNetBuildSettings
+ {
+ Configuration = configuration,
+ NoRestore = true,
+ NoIncremental = false,
+ MSBuildSettings = new DotNetMSBuildSettings
+ {
+ Version = buildVersion.Version,
+ AssemblyVersion = buildVersion.AssemblyVersion,
+ FileVersion = buildVersion.FileVersion,
+ ContinuousIntegrationBuild = BuildSystem.IsLocalBuild,
+ },
+ });
+});
+
+Task("Pack")
+ .IsDependentOn("Build")
+ .Does(() =>
+{
+ DotNetPack("./src/Cake.CodeQL.Cli/Cake.CodeQL.Cli.csproj", new DotNetPackSettings
+ {
+ Configuration = "Release",
+ NoRestore = true,
+ NoBuild = true,
+ OutputDirectory = "./artifact/nuget",
+ MSBuildSettings = new DotNetMSBuildSettings
+ {
+ Version = buildVersion.Version,
+ PackageReleaseNotes = $"https://github.com/cake-contrib/Cake.CodeQL.Cli/releases/tag/v{buildVersion.Version}"
+ }
+ });
+});
+
+Task("Push")
+ .IsDependentOn("Pack")
+ .WithCriteria(() => GitHubActions.IsRunningOnGitHubActions)
+ .WithCriteria(() => string.Equals("refs/heads/main", GitHubActions.Environment.Workflow.Ref, StringComparison.OrdinalIgnoreCase) || GitHubActions.Environment.Workflow.Ref.StartsWith("refs/tags/", StringComparison.OrdinalIgnoreCase))
+ .WithCriteria(() => ArgumentOrDefault("NUGET_PUSH"))
+ .Does(context =>
+{
+ var url = context.ArgumentOrDefault("NUGET_URL");
+ if (string.IsNullOrWhiteSpace(url))
+ {
+ context.Information("No NuGet URL specified. Skipping publishing of NuGet packages");
+ return;
+ }
+
+ var apiKey = context.ArgumentOrDefault("NUGET_API_KEY");
+ if (string.IsNullOrWhiteSpace(apiKey))
+ {
+ context.Information("No NuGet API key specified. Skipping publishing of NuGet packages");
+ return;
+ }
+
+ var nugetPushSettings = new DotNetNuGetPushSettings
+ {
+ Source = url,
+ ApiKey = apiKey,
+ SkipDuplicate = true
+ };
+
+ foreach (var nugetPackageFile in GetFiles("./artifact/nuget/*.nupkg"))
+ DotNetNuGetPush(nugetPackageFile.FullPath, nugetPushSettings);
+});
+
+Task("Publish")
+ .IsDependentOn("Push")
+ .WithCriteria(() => GetFiles("./artifact/nuget/**/*")?.Count > 0)
+ .WithCriteria(() => GitHubActions.IsRunningOnGitHubActions)
+ .WithCriteria(() => string.Equals("refs/heads/main", GitHubActions.Environment.Workflow.Ref, StringComparison.OrdinalIgnoreCase) || GitHubActions.Environment.Workflow.Ref.StartsWith("refs/tags/", StringComparison.OrdinalIgnoreCase))
+ .Does(async () =>
+ await GitHubActions.Commands.UploadArtifact(Directory("./artifact/nuget"), $"Cake.CodeQL.Cli.{buildVersion.Version}"));
+
+Task("Default")
+ .IsDependentOn("Publish");
+
+RunTarget(target);
\ No newline at end of file
diff --git a/cake.config b/cake.config
new file mode 100644
index 0000000..513b1e8
--- /dev/null
+++ b/cake.config
@@ -0,0 +1,12 @@
+[Nuget]
+Source=https://api.nuget.org/v3/index.json
+UseInProcessClient=true
+LoadDependencies=false
+
+[Paths]
+Tools=./.cake
+Addins=./.cake/addins
+Modules=./.cake/modules
+
+[Settings]
+SkipVerification=false
diff --git a/src/Cake.CodeQL.Cli/Cake.CodeQL.Cli.csproj b/src/Cake.CodeQL.Cli/Cake.CodeQL.Cli.csproj
index e39a3ce..31398cb 100644
--- a/src/Cake.CodeQL.Cli/Cake.CodeQL.Cli.csproj
+++ b/src/Cake.CodeQL.Cli/Cake.CodeQL.Cli.csproj
@@ -14,7 +14,7 @@
true
- 3.0.0
+ 0.0.0
Cake.CodeQL.Cli
Cake.CodeQL.Cli is a set of Cake aliases that integrate with GitHub Advanced Security (GAS). GAS uses CodeQL to find vulnerabilities in your code. The code must be hosted GitHub or GitHub Enterprise.
louisfischer, cake-contrib
diff --git a/src/Cake.CodeQL.Cli/CodeQLResolveToolPath.cs b/src/Cake.CodeQL.Cli/CodeQLResolveToolPath.cs
new file mode 100644
index 0000000..3ce509f
--- /dev/null
+++ b/src/Cake.CodeQL.Cli/CodeQLResolveToolPath.cs
@@ -0,0 +1,30 @@
+namespace Cake.CodeQL.Cli;
+
+internal class CodeQLResolveToolPath
+{
+ private readonly IFileSystem fileSystem;
+ private readonly ICakeEnvironment environment;
+
+ public CodeQLResolveToolPath(IFileSystem fileSystem, ICakeEnvironment environment)
+ {
+ this.fileSystem = fileSystem;
+ this.environment = environment;
+ }
+
+ public IEnumerable Find(IEnumerable toolNames, DirectoryPath dir)
+ {
+ if (dir == null || toolNames == null || toolNames?.Count() < 1) return null;
+
+ var globSettings = new GlobberSettings()
+ {
+ IsCaseSensitive = false,
+ FilePredicate = file => toolNames.Any(toolName => toolName.Equals(file.Path.GetFilename().ToString(), StringComparison.OrdinalIgnoreCase))
+ };
+
+ var globPattern = $"{dir.MakeAbsolute(environment).ToString().TrimEnd('/', '\\')}/**/*";
+
+ var globber = new Globber(fileSystem, environment);
+
+ return globber.Match(globPattern, globSettings).OfType();
+ }
+}
diff --git a/src/Cake.CodeQL.Cli/CodeQLTool.cs b/src/Cake.CodeQL.Cli/CodeQLTool.cs
index 4409c71..2217368 100644
--- a/src/Cake.CodeQL.Cli/CodeQLTool.cs
+++ b/src/Cake.CodeQL.Cli/CodeQLTool.cs
@@ -7,6 +7,9 @@ namespace Cake.CodeQL.Cli;
public abstract class CodeQLTool : Tool
where TSettings : CodeQLToolSettings
{
+ private readonly IFileSystem fileSystem;
+ private readonly ICakeEnvironment environment;
+
///
/// Initializes a new instance of the class.
///
@@ -18,6 +21,8 @@ public abstract class CodeQLTool : Tool
protected CodeQLTool(IFileSystem fileSystem, ICakeEnvironment environment, IProcessRunner processRunner, IToolLocator tools, ICakeLog log)
: base(fileSystem, environment, processRunner, tools)
{
+ this.fileSystem = fileSystem;
+ this.environment = environment;
CakeLog = log;
}
@@ -36,7 +41,24 @@ protected CodeQLTool(IFileSystem fileSystem, ICakeEnvironment environment, IProc
/// Gets the possible names of the tool executable.
///
/// The tool executable name.
- protected sealed override IEnumerable GetToolExecutableNames() => new[] { "codeql", "codeql.exe" };
+ protected sealed override IEnumerable GetToolExecutableNames() => new[] { "codeql.exe", "codeql" };
+
+ ///
+ /// CodeQL Installs into a subdirectory. This checks the subdirectories as well
+ ///
+ ///
+ ///
+ protected override IEnumerable GetAlternativeToolPaths(TSettings settings)
+ {
+ var toolResolver = new CodeQLResolveToolPath(fileSystem, environment);
+
+ var toolPaths = toolResolver.Find(GetToolExecutableNames(), settings.WorkingDirectory.Combine("tools"));
+
+ if(toolPaths == null || toolPaths.Count() < 1)
+ return base.GetAlternativeToolPaths(settings);
+
+ return toolPaths;
+ }
///
/// Runss CodeQL
diff --git a/src/Cake.CodeQL.Cli/Install/CodeQLInstallTool.cs b/src/Cake.CodeQL.Cli/Install/CodeQLInstallTool.cs
index 7293df2..cfe649a 100644
--- a/src/Cake.CodeQL.Cli/Install/CodeQLInstallTool.cs
+++ b/src/Cake.CodeQL.Cli/Install/CodeQLInstallTool.cs
@@ -1,3 +1,6 @@
+using Cake.Common.Tools.Command;
+using System;
+
namespace Cake.CodeQL.Cli.Install;
///
@@ -6,6 +9,7 @@ namespace Cake.CodeQL.Cli.Install;
public class CodeQLInstallTool
{
private readonly ICakeContext _context;
+ private readonly ICollection _executableNames = new[] { "codeql.exe", "codeql", };
///
/// Initializes a new instance of the class.
@@ -44,8 +48,8 @@ public void Install(CodeQLInstallToolSettings settings)
try { if (_context.FileExists(outFilePath)) _context.DeleteFile(outFilePath); } catch { }
}
- // 4. Verifies that the CodeQL CLI is correctly set up to create and analyze databases.
- VerifyCodeQL();
+ // 5. Verifies that the CodeQL CLI is correctly set up to create and analyze databases.
+ VerifyCodeQL(settings);
}
///
@@ -88,7 +92,24 @@ private void ExtractCodeQL(FilePath outFilePath, DirectoryPath installDir)
_context.StartProcess("tar", new ProcessSettings { Arguments = argBuilder });
}
- private void VerifyCodeQL() => _context.Command(toolExecutableNames: new[] { "codeql", "codeql.exe" }, arguments: "resolve qlpacks");
+ private void VerifyCodeQL(CodeQLInstallToolSettings settings)
+ {
+ var toolResolver = new CodeQLResolveToolPath(_context.FileSystem, _context.Environment);
+ var toolPaths = toolResolver.Find(_executableNames, settings.WorkingDirectory);
+
+ var exePath = toolPaths.FirstOrDefault(tp => _context.IsRunningOnWindows() && tp.HasExtension);
+
+ _context.Command
+ (
+ toolExecutableNames: _executableNames,
+ arguments: "resolve qlpacks",
+ settingsCustomization: cmdSettings =>
+ {
+ cmdSettings.ToolPath = exePath;
+ return cmdSettings;
+ }
+ );
+ }
private DirectoryPath GetInstallDirectory(CodeQLInstallToolSettings settings) =>
settings.InstallDirectory != null ? _context.MakeAbsolute(settings.InstallDirectory) : _context.MakeAbsolute(GetWorkingDirectory(settings).Combine("tools/codeql"));
diff --git a/src/Cake.CodeQL.Cli/Report/CodeQLSecurityReportTool.cs b/src/Cake.CodeQL.Cli/Report/CodeQLSecurityReportTool.cs
index 8441b20..46cf731 100644
--- a/src/Cake.CodeQL.Cli/Report/CodeQLSecurityReportTool.cs
+++ b/src/Cake.CodeQL.Cli/Report/CodeQLSecurityReportTool.cs
@@ -1,4 +1,6 @@
-namespace Cake.CodeQL.Cli.Report;
+using System;
+
+namespace Cake.CodeQL.Cli.Report;
///
/// Tool for generating a pdf summery of GitHub Security report
@@ -8,6 +10,9 @@
///
public class CodeQLSecurityReportTool : Tool
{
+ private readonly IFileSystem fileSystem;
+ private readonly ICakeEnvironment environment;
+
///
/// Initializes a new instance of the class.
///
@@ -17,7 +22,15 @@ public class CodeQLSecurityReportTool : Tool
/// The tool locator.
/// Cake log instance.
public CodeQLSecurityReportTool(IFileSystem fileSystem, ICakeEnvironment environment, IProcessRunner processRunner, IToolLocator tools, ICakeLog log)
- : base(fileSystem, environment, processRunner, tools) => CakeLog = log;
+ : base(fileSystem, environment, processRunner, tools)
+ {
+ this.fileSystem = fileSystem;
+ this.environment = environment;
+ this.environment = environment;
+ this.fileSystem = fileSystem;
+ CakeLog = log;
+ }
+
///
/// Cake log instance.
@@ -36,6 +49,19 @@ protected sealed override IEnumerable GetToolExecutableNames() => new[]
"github-security-report-linux-x64"
};
+
+ protected override IEnumerable GetAlternativeToolPaths(CodeQLSecurityReportToolSettings settings)
+ {
+ var toolResolver = new CodeQLResolveToolPath(fileSystem, environment);
+
+ var toolPaths = toolResolver.Find(GetToolExecutableNames(), settings.WorkingDirectory.Combine("tools"));
+
+ if (toolPaths == null || toolPaths.Count() < 1)
+ return base.GetAlternativeToolPaths(settings);
+
+ return toolPaths;
+ }
+
///
/// Gets the name of the tool.
///
diff --git a/src/Cake.CodeQL.Cli/_Usings.cs b/src/Cake.CodeQL.Cli/_Usings.cs
deleted file mode 100644
index 3e4c00c..0000000
--- a/src/Cake.CodeQL.Cli/_Usings.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-global using Cake.CodeQL.Cli.Database;
-global using Cake.CodeQL.Cli.Upload;
-global using Cake.Common;
-global using Cake.Common.IO;
-global using Cake.Common.Net;
-global using Cake.Common.Tools.Command;
-global using Cake.Core;
-global using Cake.Core.Annotations;
-global using Cake.Core.Diagnostics;
-global using Cake.Core.IO;
-global using Cake.Core.Tooling;
-global using System.Reflection;