mirror of
https://github.com/github/codeql.git
synced 2026-02-28 12:53:49 +01:00
151 lines
6.5 KiB
C#
151 lines
6.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Security.Cryptography.X509Certificates;
|
|
using Semmle.Util;
|
|
using Semmle.Util.Logging;
|
|
using Newtonsoft.Json;
|
|
using System.Linq;
|
|
|
|
namespace Semmle.Extraction.CSharp.DependencyFetching
|
|
{
|
|
public class DependabotProxy : IDisposable
|
|
{
|
|
/// <summary>
|
|
/// Represents configurations for package registries.
|
|
/// </summary>
|
|
/// <param name="Type">The type of package registry.</param>
|
|
/// <param name="URL">The URL of the package registry.</param>
|
|
public record class RegistryConfig(string Type, string URL);
|
|
|
|
private readonly string host;
|
|
private readonly string port;
|
|
|
|
/// <summary>
|
|
/// The full address of the Dependabot proxy, if available.
|
|
/// </summary>
|
|
internal string Address { get; }
|
|
/// <summary>
|
|
/// The URLs of package registries that are configured for the proxy.
|
|
/// </summary>
|
|
internal HashSet<string> RegistryURLs { get; }
|
|
/// <summary>
|
|
/// The path to the temporary file where the certificate is stored.
|
|
/// </summary>
|
|
internal string? CertificatePath { get; private set; }
|
|
/// <summary>
|
|
/// The certificate used for the Dependabot proxy.
|
|
/// </summary>
|
|
internal X509Certificate2? Certificate { get; private set; }
|
|
|
|
internal static DependabotProxy? GetDependabotProxy(
|
|
ILogger logger, IDiagnosticsWriter diagnosticsWriter, TemporaryDirectory tempWorkingDirectory)
|
|
{
|
|
// Setting HTTP(S)_PROXY and SSL_CERT_FILE have no effect on Windows or macOS,
|
|
// but we would still end up using the Dependabot proxy to check for feed reachability.
|
|
// This would result in us discovering that the feeds are reachable, but `dotnet` would
|
|
// fail to connect to them. To prevent this from happening, we do not initialise an
|
|
// instance of `DependabotProxy` on those platforms.
|
|
if (SystemBuildActions.Instance.IsWindows() || SystemBuildActions.Instance.IsMacOs()) return null;
|
|
|
|
// Obtain and store the address of the Dependabot proxy, if available.
|
|
var host = Environment.GetEnvironmentVariable(EnvironmentVariableNames.ProxyHost);
|
|
var port = Environment.GetEnvironmentVariable(EnvironmentVariableNames.ProxyPort);
|
|
|
|
if (string.IsNullOrWhiteSpace(host) || string.IsNullOrWhiteSpace(port))
|
|
{
|
|
logger.LogInfo("No Dependabot proxy credentials are configured.");
|
|
return null;
|
|
}
|
|
|
|
var result = new DependabotProxy(host, port);
|
|
logger.LogInfo($"Dependabot proxy configured at {result.Address}");
|
|
|
|
// Obtain and store the proxy's certificate, if available.
|
|
var cert = Environment.GetEnvironmentVariable(EnvironmentVariableNames.ProxyCertificate);
|
|
|
|
if (!string.IsNullOrWhiteSpace(cert))
|
|
{
|
|
var certDirPath = new DirectoryInfo(Path.Join(tempWorkingDirectory.DirInfo.FullName, ".dependabot-proxy"));
|
|
Directory.CreateDirectory(certDirPath.FullName);
|
|
|
|
result.CertificatePath = Path.Join(certDirPath.FullName, "proxy.crt");
|
|
var certFile = new FileInfo(result.CertificatePath);
|
|
|
|
using var writer = certFile.CreateText();
|
|
writer.Write(cert);
|
|
writer.Close();
|
|
|
|
logger.LogInfo($"Stored Dependabot proxy certificate at {result.CertificatePath}");
|
|
|
|
result.Certificate = X509Certificate2.CreateFromPem(cert);
|
|
}
|
|
|
|
// Try to obtain the list of private registry URLs.
|
|
var registryURLs = Environment.GetEnvironmentVariable(EnvironmentVariableNames.ProxyURLs);
|
|
|
|
if (!string.IsNullOrWhiteSpace(registryURLs))
|
|
{
|
|
try
|
|
{
|
|
// The value of the environment variable should be a JSON array of objects, such as:
|
|
// [ { "type": "nuget_feed", "url": "https://nuget.pkg.github.com/org/index.json" } ]
|
|
var array = JsonConvert.DeserializeObject<List<RegistryConfig>>(registryURLs);
|
|
if (array is not null)
|
|
{
|
|
foreach (RegistryConfig config in array)
|
|
{
|
|
// The array contains all configured private registries, not just ones for C#.
|
|
// We ignore the non-C# ones here.
|
|
if (!config.Type.Equals("nuget_feed"))
|
|
{
|
|
logger.LogDebug($"Ignoring registry at '{config.URL}' since it is not of type 'nuget_feed'.");
|
|
continue;
|
|
}
|
|
|
|
logger.LogInfo($"Found private registry at '{config.URL}'");
|
|
result.RegistryURLs.Add(config.URL);
|
|
}
|
|
}
|
|
}
|
|
catch (JsonException ex)
|
|
{
|
|
logger.LogError($"Unable to parse '{EnvironmentVariableNames.ProxyURLs}': {ex.Message}");
|
|
}
|
|
}
|
|
|
|
// Emit a diagnostic for the discovered private registries, so that it is easy
|
|
// for users to see that they were picked up.
|
|
if (result.RegistryURLs.Count > 0)
|
|
{
|
|
diagnosticsWriter.AddEntry(new DiagnosticMessage(
|
|
Language.CSharp,
|
|
"buildless/analysis-using-private-registries",
|
|
severity: DiagnosticMessage.TspSeverity.Note,
|
|
visibility: new DiagnosticMessage.TspVisibility(true, true, true),
|
|
name: "C# extraction used private package registries",
|
|
markdownMessage: string.Format(
|
|
"C# was extracted using the following private package registries:\n\n{0}\n",
|
|
string.Join("\n", result.RegistryURLs.Select(url => string.Format("- `{0}`", url)))
|
|
)
|
|
));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private DependabotProxy(string host, string port)
|
|
{
|
|
this.host = host;
|
|
this.port = port;
|
|
this.Address = $"http://{this.host}:{this.port}";
|
|
this.RegistryURLs = new HashSet<string>();
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
this.Certificate?.Dispose();
|
|
}
|
|
}
|
|
}
|