minor fixes for the new inventory and vulnerability feature

This commit is contained in:
Oliver Kieselbach
2026-03-20 19:17:56 +01:00
parent f1d653e60e
commit 945df7c816
11 changed files with 129 additions and 96 deletions
@@ -1 +1 @@
541
544
@@ -129,11 +129,11 @@ namespace AutopilotMonitor.Functions.Functions.Vulnerability
private class UnmatchedSoftwareAgg
{
public string SoftwareName { get; set; }
public string Publisher { get; set; }
public string? SoftwareName { get; set; } = "";
public string? Publisher { get; set; } = "";
public int Frequency { get; set; }
public DateTime LastSeenAt { get; set; }
public string ExampleSessionId { get; set; }
public string? ExampleSessionId { get; set; } = "";
}
}
}
@@ -181,6 +181,9 @@ public static class EndpointAccessPolicyCatalog
new("POST", "maintenance/trigger", EndpointPolicy.GalacticAdminOnly),
new("GET", "health/detailed", EndpointPolicy.AuthenticatedUser),
new("POST", "rules/reseed-from-github", EndpointPolicy.GalacticAdminOnly),
new("GET", "vulnerability/unmatched-software", EndpointPolicy.GalacticAdminOnly),
new("POST", "vulnerability/sync", EndpointPolicy.GalacticAdminOnly),
new("POST", "vulnerability/cpe-mapping", EndpointPolicy.GalacticAdminOnly),
new("POST", "rules/ime-log-patterns/reseed", EndpointPolicy.GalacticAdminOnly),
new("GET", "feedback/all", EndpointPolicy.GalacticAdminOnly),
new("GET", "galactic/notifications", EndpointPolicy.GalacticAdminOnly),
@@ -43,7 +43,7 @@ namespace AutopilotMonitor.Functions.Services.Vulnerability
/// Check if a CVE is in the KEV catalog. Auto-refreshes if cache is stale.
/// Returns the KevEntry if found, null otherwise.
/// </summary>
public async Task<KevEntry> CheckKevAsync(string cveId)
public async Task<KevEntry?> CheckKevAsync(string? cveId)
{
await EnsureCacheAsync();
@@ -129,23 +129,23 @@ namespace AutopilotMonitor.Functions.Services.Vulnerability
public class KevCatalog
{
public string Title { get; set; }
public string CatalogVersion { get; set; }
public string DateReleased { get; set; }
public string? Title { get; set; }
public string? CatalogVersion { get; set; }
public string? DateReleased { get; set; }
public int Count { get; set; }
public List<KevEntry> Vulnerabilities { get; set; } = new List<KevEntry>();
}
public class KevEntry
{
public string CveID { get; set; }
public string VendorProject { get; set; }
public string Product { get; set; }
public string VulnerabilityName { get; set; }
public string DateAdded { get; set; }
public string ShortDescription { get; set; }
public string RequiredAction { get; set; }
public string DueDate { get; set; }
public string KnownRansomwareCampaignUse { get; set; }
public string? CveID { get; set; }
public string? VendorProject { get; set; }
public string? Product { get; set; }
public string? VulnerabilityName { get; set; }
public string? DateAdded { get; set; }
public string? ShortDescription { get; set; }
public string? RequiredAction { get; set; }
public string? DueDate { get; set; }
public string? KnownRansomwareCampaignUse { get; set; }
}
}
@@ -67,7 +67,7 @@ namespace AutopilotMonitor.Functions.Services.Vulnerability
/// Get the CVRF document for a specific monthly update (e.g., "2025-Mar").
/// Contains detailed vulnerability information per Microsoft product.
/// </summary>
public async Task<MsrcCvrfDocument> GetCvrfAsync(string documentId, CancellationToken ct = default)
public async Task<MsrcCvrfDocument?> GetCvrfAsync(string documentId, CancellationToken ct = default)
{
try
{
@@ -105,40 +105,40 @@ namespace AutopilotMonitor.Functions.Services.Vulnerability
public class MsrcUpdateSummary
{
public string ID { get; set; }
public string Alias { get; set; }
public string DocumentTitle { get; set; }
public string InitialReleaseDate { get; set; }
public string CurrentReleaseDate { get; set; }
public string CvrfUrl { get; set; }
public string? ID { get; set; }
public string? Alias { get; set; }
public string? DocumentTitle { get; set; }
public string? InitialReleaseDate { get; set; }
public string? CurrentReleaseDate { get; set; }
public string? CvrfUrl { get; set; }
}
public class MsrcCvrfDocument
{
public MsrcDocumentTitle DocumentTitle { get; set; }
public MsrcDocumentTracking DocumentTracking { get; set; }
public MsrcProductTree ProductTree { get; set; }
public MsrcDocumentTitle? DocumentTitle { get; set; }
public MsrcDocumentTracking? DocumentTracking { get; set; }
public MsrcProductTree? ProductTree { get; set; }
public List<MsrcVulnerability> Vulnerability { get; set; } = new List<MsrcVulnerability>();
}
public class MsrcDocumentTitle
{
public string Value { get; set; }
public string? Value { get; set; }
}
public class MsrcDocumentTracking
{
public MsrcRevisionHistory Identification { get; set; }
public MsrcRevisionHistory? Identification { get; set; }
}
public class MsrcRevisionHistory
{
public MsrcDocumentId ID { get; set; }
public MsrcDocumentId? ID { get; set; }
}
public class MsrcDocumentId
{
public string Value { get; set; }
public string? Value { get; set; }
}
public class MsrcProductTree
@@ -149,23 +149,23 @@ namespace AutopilotMonitor.Functions.Services.Vulnerability
public class MsrcBranch
{
public string Type { get; set; }
public string Name { get; set; }
public string? Type { get; set; }
public string? Name { get; set; }
public List<MsrcBranch> Items { get; set; } = new List<MsrcBranch>();
}
public class MsrcFullProductName
{
public string ProductID { get; set; }
public string Value { get; set; }
public string? ProductID { get; set; }
public string? Value { get; set; }
}
public class MsrcVulnerability
{
public MsrcOrdinal Ordinal { get; set; }
public MsrcCveTitle Title { get; set; }
public MsrcOrdinal? Ordinal { get; set; }
public MsrcCveTitle? Title { get; set; }
public List<MsrcNote> Notes { get; set; } = new List<MsrcNote>();
public MsrcCveNumber CVE { get; set; }
public MsrcCveNumber? CVE { get; set; }
public List<MsrcProductStatus> ProductStatuses { get; set; } = new List<MsrcProductStatus>();
public List<MsrcThreat> Threats { get; set; } = new List<MsrcThreat>();
public List<MsrcCvssScoreSet> CVSSScoreSets { get; set; } = new List<MsrcCvssScoreSet>();
@@ -173,49 +173,49 @@ namespace AutopilotMonitor.Functions.Services.Vulnerability
public class MsrcOrdinal
{
public string Value { get; set; }
public string? Value { get; set; }
}
public class MsrcCveTitle
{
public string Value { get; set; }
public string? Value { get; set; }
}
public class MsrcCveNumber
{
public string Value { get; set; }
public string? Value { get; set; }
}
public class MsrcNote
{
public string Title { get; set; }
public string Type { get; set; }
public string Value { get; set; }
public string? Title { get; set; }
public string? Type { get; set; }
public string? Value { get; set; }
}
public class MsrcProductStatus
{
public string Type { get; set; }
public string? Type { get; set; }
public List<string> ProductID { get; set; } = new List<string>();
}
public class MsrcThreat
{
public string Type { get; set; }
public MsrcThreatDescription Description { get; set; }
public string? Type { get; set; }
public MsrcThreatDescription? Description { get; set; }
public List<string> ProductID { get; set; } = new List<string>();
}
public class MsrcThreatDescription
{
public string Value { get; set; }
public string? Value { get; set; }
}
public class MsrcCvssScoreSet
{
public double BaseScore { get; set; }
public string TemporalScore { get; set; }
public string Vector { get; set; }
public string? TemporalScore { get; set; }
public string? Vector { get; set; }
public List<string> ProductID { get; set; } = new List<string>();
}
}
@@ -83,7 +83,7 @@ namespace AutopilotMonitor.Functions.Services.Vulnerability
using var request = new HttpRequestMessage(HttpMethod.Get, url);
if (hasApiKey)
{
request.Headers.Add("apiKey", adminConfig.NvdApiKey);
request.Headers.Add("apiKey", adminConfig!.NvdApiKey);
}
request.Headers.Add("User-Agent", "AutopilotMonitor/1.0");
@@ -123,23 +123,23 @@ namespace AutopilotMonitor.Functions.Services.Vulnerability
public class NvdVulnerabilityItem
{
public NvdCve Cve { get; set; }
public NvdCve? Cve { get; set; }
}
public class NvdCve
{
public string Id { get; set; }
public string? Id { get; set; }
public List<NvdDescription> Descriptions { get; set; } = new List<NvdDescription>();
public NvdMetrics Metrics { get; set; }
public NvdMetrics? Metrics { get; set; }
public List<NvdConfiguration> Configurations { get; set; } = new List<NvdConfiguration>();
public string Published { get; set; }
public string LastModified { get; set; }
public string? Published { get; set; }
public string? LastModified { get; set; }
}
public class NvdDescription
{
public string Lang { get; set; }
public string Value { get; set; }
public string? Lang { get; set; }
public string? Value { get; set; }
}
public class NvdMetrics
@@ -150,14 +150,14 @@ namespace AutopilotMonitor.Functions.Services.Vulnerability
public class NvdCvssMetricV31
{
public NvdCvssData CvssData { get; set; }
public NvdCvssData? CvssData { get; set; }
}
public class NvdCvssData
{
public double BaseScore { get; set; }
public string BaseSeverity { get; set; }
public string VectorString { get; set; }
public string? BaseSeverity { get; set; }
public string? VectorString { get; set; }
}
public class NvdConfiguration
@@ -167,7 +167,7 @@ namespace AutopilotMonitor.Functions.Services.Vulnerability
public class NvdNode
{
public string Operator { get; set; }
public string? Operator { get; set; }
public bool Negate { get; set; }
public List<NvdCpeMatch> CpeMatch { get; set; } = new List<NvdCpeMatch>();
}
@@ -175,11 +175,11 @@ namespace AutopilotMonitor.Functions.Services.Vulnerability
public class NvdCpeMatch
{
public bool Vulnerable { get; set; }
public string Criteria { get; set; }
public string VersionStartIncluding { get; set; }
public string VersionStartExcluding { get; set; }
public string VersionEndIncluding { get; set; }
public string VersionEndExcluding { get; set; }
public string? Criteria { get; set; }
public string? VersionStartIncluding { get; set; }
public string? VersionStartExcluding { get; set; }
public string? VersionEndIncluding { get; set; }
public string? VersionEndExcluding { get; set; }
}
// CPE search response
@@ -191,19 +191,19 @@ namespace AutopilotMonitor.Functions.Services.Vulnerability
public class NvdCpeProduct
{
public NvdCpeEntry Cpe { get; set; }
public NvdCpeEntry? Cpe { get; set; }
}
public class NvdCpeEntry
{
public string CpeName { get; set; }
public string CpeNameId { get; set; }
public string? CpeName { get; set; }
public string? CpeNameId { get; set; }
public List<NvdCpeTitle> Titles { get; set; } = new List<NvdCpeTitle>();
}
public class NvdCpeTitle
{
public string Title { get; set; }
public string Lang { get; set; }
public string? Title { get; set; }
public string? Lang { get; set; }
}
}
@@ -42,10 +42,10 @@ namespace AutopilotMonitor.Functions.Services.Vulnerability
/// </summary>
public static bool IsVersionAffected(
string installedVersion,
string versionStartIncluding,
string versionStartExcluding,
string versionEndIncluding,
string versionEndExcluding)
string? versionStartIncluding,
string? versionStartExcluding,
string? versionEndIncluding,
string? versionEndExcluding)
{
if (string.IsNullOrWhiteSpace(installedVersion))
return false;
@@ -22,7 +22,7 @@ namespace AutopilotMonitor.Functions.Services.Vulnerability
private readonly AdminConfigurationService _adminConfig;
private readonly ILogger<VulnerabilityCorrelationService> _logger;
private List<CpeMappingEntry> _cpeMappings;
private List<CpeMappingEntry>? _cpeMappings;
private static readonly SemaphoreSlim _initLock = new SemaphoreSlim(1, 1);
private static bool _seedLoaded = false;
@@ -101,7 +101,7 @@ namespace AutopilotMonitor.Functions.Services.Vulnerability
}
matchedCount++;
var cpeUri = cpeMapping.CpeUri;
var cpeUri = cpeMapping.CpeUri ?? "";
// Look up CVEs
List<Dictionary<string, object>> vulns;
@@ -254,7 +254,7 @@ namespace AutopilotMonitor.Functions.Services.Vulnerability
// CPE Mapping
// -----------------------------------------------------------------------
private CpeMappingEntry FindCpeMapping(string normalizedVendor, string normalizedName, string displayName)
private CpeMappingEntry? FindCpeMapping(string normalizedVendor, string normalizedName, string displayName)
{
if (_cpeMappings == null || _cpeMappings.Count == 0)
return null;
@@ -477,9 +477,9 @@ namespace AutopilotMonitor.Functions.Services.Vulnerability
CpeUri = entity.GetString("CpeUri") ?? "",
Category = entity.GetString("Category") ?? "custom",
DisplayNamePatterns = JsonSerializer.Deserialize<List<string>>(
entity.GetString("DisplayNamePatternsJson") ?? "[]"),
entity.GetString("DisplayNamePatternsJson") ?? "[]") ?? new List<string>(),
PublisherPatterns = JsonSerializer.Deserialize<List<string>>(
entity.GetString("PublisherPatternsJson") ?? "[]")
entity.GetString("PublisherPatternsJson") ?? "[]") ?? new List<string>()
});
}
}
@@ -507,9 +507,9 @@ namespace AutopilotMonitor.Functions.Services.Vulnerability
CpeUri = entity.GetString("CpeUri") ?? "",
Category = entity.GetString("Category") ?? "community",
DisplayNamePatterns = JsonSerializer.Deserialize<List<string>>(
entity.GetString("DisplayNamePatternsJson") ?? "[]"),
entity.GetString("DisplayNamePatternsJson") ?? "[]") ?? new List<string>(),
PublisherPatterns = JsonSerializer.Deserialize<List<string>>(
entity.GetString("PublisherPatternsJson") ?? "[]")
entity.GetString("PublisherPatternsJson") ?? "[]") ?? new List<string>()
});
communityCount++;
}
@@ -571,24 +571,24 @@ namespace AutopilotMonitor.Functions.Services.Vulnerability
public class CpeMappingSeed
{
public string Version { get; set; }
public string LastUpdated { get; set; }
public string? Version { get; set; }
public string? LastUpdated { get; set; }
public List<CpeMappingEntry> Mappings { get; set; } = new List<CpeMappingEntry>();
}
public class CpeMappingEntry
{
public string NormalizedVendor { get; set; }
public string NormalizedProduct { get; set; }
public string? NormalizedVendor { get; set; }
public string? NormalizedProduct { get; set; }
public List<string> DisplayNamePatterns { get; set; } = new List<string>();
public List<string> PublisherPatterns { get; set; } = new List<string>();
public string CpeVendor { get; set; }
public string CpeProduct { get; set; }
public string CpeUri { get; set; }
public string Category { get; set; }
public string? CpeVendor { get; set; }
public string? CpeProduct { get; set; }
public string? CpeUri { get; set; }
public string? Category { get; set; }
// Set during matching -- not serialized
[JsonIgnore]
public string MatchConfidence { get; set; }
public string? MatchConfidence { get; set; }
}
}
@@ -565,9 +565,6 @@ export default function VulnerabilityReportSection({
Data Freshness: {dataFreshness}
</div>
)}
<p className="text-xs text-gray-400 mt-2 italic">
This product uses the NVD API but is not endorsed or certified by the NVD.
</p>
</>
)}
</div>
@@ -38,6 +38,39 @@ export default function TermsPage() {
</div>
</div>
<div className="bg-white rounded-lg shadow p-6 space-y-4">
<h2 className="text-xl font-semibold text-gray-900">Third-Party Data Sources & Attributions</h2>
<p className="text-gray-700">
The vulnerability correlation feature uses the following external data sources to identify known vulnerabilities in installed software:
</p>
<div className="space-y-3">
<div className="p-4 border border-gray-200 rounded-lg">
<h3 className="font-semibold text-gray-900 mb-1">National Vulnerability Database (NVD)</h3>
<p className="text-sm text-gray-700 mb-2">
This product uses the NVD API but is not endorsed or certified by the NVD.
</p>
<p className="text-sm text-gray-500">
The NVD is maintained by the National Institute of Standards and Technology (NIST). CVE and CPE data is sourced from the NVD API 2.0. For more information, visit{" "}
<a href="https://nvd.nist.gov/" target="_blank" rel="noopener noreferrer" className="text-indigo-600 hover:text-indigo-800 underline">nvd.nist.gov</a>.
</p>
</div>
<div className="p-4 border border-gray-200 rounded-lg">
<h3 className="font-semibold text-gray-900 mb-1">CISA Known Exploited Vulnerabilities (KEV) Catalog</h3>
<p className="text-sm text-gray-500">
Actively exploited vulnerability data is sourced from the CISA KEV Catalog maintained by the Cybersecurity and Infrastructure Security Agency. For more information, visit{" "}
<a href="https://www.cisa.gov/known-exploited-vulnerabilities-catalog" target="_blank" rel="noopener noreferrer" className="text-indigo-600 hover:text-indigo-800 underline">cisa.gov</a>.
</p>
</div>
<div className="p-4 border border-gray-200 rounded-lg">
<h3 className="font-semibold text-gray-900 mb-1">Microsoft Security Response Center (MSRC)</h3>
<p className="text-sm text-gray-500">
Microsoft-specific vulnerability data is sourced from the MSRC Security Update Guide API. For more information, visit{" "}
<a href="https://msrc.microsoft.com/" target="_blank" rel="noopener noreferrer" className="text-indigo-600 hover:text-indigo-800 underline">msrc.microsoft.com</a>.
</p>
</div>
</div>
</div>
</main>
</div>
);
File diff suppressed because one or more lines are too long