Skip to content

Add Linux client support (.NET 8) for cross-platform Secure Boot monitoring#10

Open
Copilot wants to merge 50 commits into
mainfrom
copilot/add-linux-client-support
Open

Add Linux client support (.NET 8) for cross-platform Secure Boot monitoring#10
Copilot wants to merge 50 commits into
mainfrom
copilot/add-linux-client-support

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Nov 7, 2025

Implements Linux client as specified in v2.0 roadmap to enable Secure Boot certificate monitoring on UEFI-enabled Linux systems.

New Components

SecureBootWatcher.LinuxClient (.NET 8)

  • LinuxRegistrySnapshotProvider: Reads EFI variable status from /sys/firmware/efi/efivars
  • LinuxEventLogReader: Queries systemd journald via journalctl for boot events
  • LinuxSecureBootCertificateEnumerator: Parses X.509 certificates directly from EFI variables (db, dbx, KEK, PK)
  • ReportBuilder: Reads hardware metadata from DMI/SMBIOS (/sys/class/dmi/id/)

All existing sinks (File Share, Azure Queue, Web API) and storage components work unchanged on Linux.

SecureBootWatcher.LinuxClient.Tests

Basic unit test coverage for Linux-specific providers.

Architecture

// Same interface, platform-specific implementation
public interface ISecureBootCertificateEnumerator
{
    Task<SecureBootCertificateCollection> EnumerateAsync(CancellationToken ct);
}

// Windows: PowerShell Get-SecureBootUEFI
// Linux: Direct EFI variable read from /sys/firmware/efi/efivars

Separate project from Windows client due to incompatible frameworks (.NET Framework 4.8 vs .NET 8) and platform APIs (Registry/EventLog vs EFI vars/journald).

System Requirements

  • Linux with UEFI firmware (Ubuntu 20.04+, RHEL 8+, Debian 11+)
  • .NET 8 runtime or self-contained deployment
  • Root privileges (read-only access to /sys/firmware/efi/efivars)
  • systemd with journald

Documentation

  • Main README updated with Linux client information and runtime requirements
  • New SecureBootWatcher.LinuxClient/README.md with installation, systemd service setup, and troubleshooting
  • Implementation summary in docs/LINUX_CLIENT_IMPLEMENTATION_SUMMARY.md

Bug Fix

Fixed .NET Framework 4.8 compilation error in PowerShellSecureBootCertificateEnumerator where String.Contains(string, StringComparison) overload is unavailable. Changed to IndexOf(string, StringComparison) >= 0.

Original prompt

This section details on the original issue you should resolve

<issue_title>Linux client support (.NET 8)</issue_title>
<issue_description>Implement Linux client support (.NET 8) as described in roadmap</issue_description>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 5 commits November 7, 2025 06:08
…T Framework 4.8

Co-authored-by: robgrame <12012136+robgrame@users.noreply.github.com>
Co-authored-by: robgrame <12012136+robgrame@users.noreply.github.com>
Co-authored-by: robgrame <12012136+robgrame@users.noreply.github.com>
Co-authored-by: robgrame <12012136+robgrame@users.noreply.github.com>
Co-authored-by: robgrame <12012136+robgrame@users.noreply.github.com>
Copilot AI changed the title [WIP] Implement Linux client support for .NET 8 Add Linux client support (.NET 8) for cross-platform Secure Boot monitoring Nov 7, 2025
Copilot AI requested a review from robgrame November 7, 2025 06:34
@robgrame robgrame requested a review from Copilot November 7, 2025 12:42
@robgrame robgrame marked this pull request as ready for review November 7, 2025 12:42
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements Linux client support (.NET 8) for the SecureBootWatcher solution, enabling cross-platform Secure Boot certificate monitoring. The implementation creates a new .NET 8 console application that uses Linux-specific APIs to achieve feature parity with the existing Windows client.

Key changes:

  • New Linux client project with platform-specific EFI variable access, journald event logging, and DMI/SMBIOS hardware detection
  • Shared sink implementations (File, Azure Queue, Web API) reused across platforms
  • Comprehensive documentation and unit tests
  • Bug fix for .NET Framework 4.8 compatibility in existing Windows client

Reviewed Changes

Copilot reviewed 31 out of 33 changed files in this pull request and generated 38 comments.

Show a summary per file
File Description
docs/LINUX_CLIENT_IMPLEMENTATION_SUMMARY.md Comprehensive implementation summary documenting architecture, decisions, and deliverables
SecureBootWatcher.sln Added Linux client and test projects to solution
SecureBootWatcher.LinuxClient/*.cs New Linux client implementation with platform-specific services
SecureBootWatcher.LinuxClient/README.md Detailed documentation for Linux client setup, configuration, and troubleshooting
SecureBootWatcher.LinuxClient.Tests/*.cs Unit tests for Linux-specific components
README.md Updated with Linux client information and prerequisites
SecureBootWatcher.Client/Services/PowerShellSecureBootCertificateEnumerator.cs Fixed .NET Framework 4.8 compatibility issue
Comments suppressed due to low confidence (3)

SecureBootWatcher.LinuxClient/Sinks/AzureQueueReportSink.cs:1

  • Comment is in Italian. Should be translated to English: 'Method 3: Certificate-based authentication (MORE SECURE - recommended for production)'.
using System;

SecureBootWatcher.LinuxClient/Sinks/AzureQueueReportSink.cs:1

  • Comment is in Italian. Should be translated to English: 'Method 5: DefaultAzureCredential (tries multiple methods automatically)'.
using System;

SecureBootWatcher.LinuxClient/Sinks/AzureQueueReportSink.cs:1

  • Comment is in Italian. Should be translated to English: 'If a ClientId is specified, use it for Managed Identity'.
using System;

Comment thread README.md Outdated
Comment on lines +9 to +14
/// </summary>
internal interface ISecureBootCertificateEnumerator
{
/// <summary>
/// Enumerates all Secure Boot certificates from UEFI firmware.
/// </summary>
Copy link

Copilot AI Nov 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

XML documentation comments have inconsistent indentation. Lines 9 and 14 use 2 spaces instead of the standard 4 spaces used elsewhere. This should be corrected for consistency.

Suggested change
/// </summary>
internal interface ISecureBootCertificateEnumerator
{
/// <summary>
/// Enumerates all Secure Boot certificates from UEFI firmware.
/// </summary>
/// </summary>
internal interface ISecureBootCertificateEnumerator
{
/// <summary>
/// Enumerates all Secure Boot certificates from UEFI firmware.
/// </summary>

Copilot uses AI. Check for mistakes.
Comment on lines +22 to +112
{
private readonly ILogger<AzureQueueReportSink> _logger;
private readonly IOptionsMonitor<SecureBootWatcherOptions> _options;
private readonly AsyncRetryPolicy _retryPolicy;

public AzureQueueReportSink(ILogger<AzureQueueReportSink> logger, IOptionsMonitor<SecureBootWatcherOptions> options)
{
_logger = logger;
_options = options;
_retryPolicy = Policy
.Handle<RequestFailedException>()
.Or<TimeoutException>()
.WaitAndRetryAsync(3, attempt => TimeSpan.FromSeconds(Math.Pow(2, attempt)), (ex, span, attempt, _) =>
{
_logger.LogWarning(ex, "Retrying Azure Queue send attempt {Attempt} after {Delay}.", attempt, span);
});
}

public async Task EmitAsync(SecureBootStatusReport report, CancellationToken cancellationToken)
{
var sinkOptions = _options.CurrentValue.Sinks.AzureQueue;
if (string.IsNullOrWhiteSpace(sinkOptions.QueueName))
{
_logger.LogDebug("Azure Queue sink is disabled because QueueName is not configured.");
return;
}

var queueClient = CreateQueueClient(sinkOptions);
if (queueClient == null)
{
_logger.LogWarning("Azure Queue sink skipped because required configuration is missing.");
return;
}

await queueClient.CreateIfNotExistsAsync(cancellationToken: cancellationToken).ConfigureAwait(false);

var envelope = new SecureBootQueueEnvelope
{
Report = report,
EnqueuedAtUtc = DateTimeOffset.UtcNow
};

var payload = JsonSerializer.Serialize(envelope, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = false
});

await _retryPolicy.ExecuteAsync(async token =>
{
await queueClient.SendMessageAsync(
BinaryData.FromString(payload),
visibilityTimeout: sinkOptions.VisibilityTimeout,
cancellationToken: token).ConfigureAwait(false);

_logger.LogInformation("Secure Boot report enqueued to {QueueName} using {AuthMethod} authentication.",
queueClient.Name, sinkOptions.AuthenticationMethod);
}, cancellationToken).ConfigureAwait(false);
}

private QueueClient? CreateQueueClient(AzureQueueSinkOptions options)
{
try
{
// Metodo 1: Connection String (non raccomandato per produzione)
if (options.AuthenticationMethod.Equals("ConnectionString", StringComparison.OrdinalIgnoreCase) &&
!string.IsNullOrWhiteSpace(options.ConnectionString))
{
_logger.LogWarning("Using Connection String authentication. This is NOT recommended for production. Use App Registration or Managed Identity instead.");
return new QueueClient(options.ConnectionString, options.QueueName);
}

// Valida che QueueServiceUri sia configurato per autenticazione Entra ID
if (options.QueueServiceUri == null)
{
_logger.LogError("QueueServiceUri is required for Entra ID authentication.");
return null;
}

var queueUri = new Uri(options.QueueServiceUri, options.QueueName);
TokenCredential credential;

// Metodo 2: App Registration con Client Secret (raccomandato per service-to-service)
if (options.AuthenticationMethod.Equals("AppRegistration", StringComparison.OrdinalIgnoreCase))
{
if (string.IsNullOrWhiteSpace(options.TenantId) ||
string.IsNullOrWhiteSpace(options.ClientId) ||
string.IsNullOrWhiteSpace(options.ClientSecret))
{
_logger.LogError("TenantId, ClientId, and ClientSecret are required for App Registration authentication.");
return null;
Copy link

Copilot AI Nov 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent and incorrect indentation throughout the file. The class, fields, and methods use non-standard whitespace (mixing tabs and spaces). Should use consistent 4-space indentation according to C# coding conventions.

Suggested change
{
private readonly ILogger<AzureQueueReportSink> _logger;
private readonly IOptionsMonitor<SecureBootWatcherOptions> _options;
private readonly AsyncRetryPolicy _retryPolicy;
public AzureQueueReportSink(ILogger<AzureQueueReportSink> logger, IOptionsMonitor<SecureBootWatcherOptions> options)
{
_logger = logger;
_options = options;
_retryPolicy = Policy
.Handle<RequestFailedException>()
.Or<TimeoutException>()
.WaitAndRetryAsync(3, attempt => TimeSpan.FromSeconds(Math.Pow(2, attempt)), (ex, span, attempt, _) =>
{
_logger.LogWarning(ex, "Retrying Azure Queue send attempt {Attempt} after {Delay}.", attempt, span);
});
}
public async Task EmitAsync(SecureBootStatusReport report, CancellationToken cancellationToken)
{
var sinkOptions = _options.CurrentValue.Sinks.AzureQueue;
if (string.IsNullOrWhiteSpace(sinkOptions.QueueName))
{
_logger.LogDebug("Azure Queue sink is disabled because QueueName is not configured.");
return;
}
var queueClient = CreateQueueClient(sinkOptions);
if (queueClient == null)
{
_logger.LogWarning("Azure Queue sink skipped because required configuration is missing.");
return;
}
await queueClient.CreateIfNotExistsAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
var envelope = new SecureBootQueueEnvelope
{
Report = report,
EnqueuedAtUtc = DateTimeOffset.UtcNow
};
var payload = JsonSerializer.Serialize(envelope, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = false
});
await _retryPolicy.ExecuteAsync(async token =>
{
await queueClient.SendMessageAsync(
BinaryData.FromString(payload),
visibilityTimeout: sinkOptions.VisibilityTimeout,
cancellationToken: token).ConfigureAwait(false);
_logger.LogInformation("Secure Boot report enqueued to {QueueName} using {AuthMethod} authentication.",
queueClient.Name, sinkOptions.AuthenticationMethod);
}, cancellationToken).ConfigureAwait(false);
}
private QueueClient? CreateQueueClient(AzureQueueSinkOptions options)
{
try
{
// Metodo 1: Connection String (non raccomandato per produzione)
if (options.AuthenticationMethod.Equals("ConnectionString", StringComparison.OrdinalIgnoreCase) &&
!string.IsNullOrWhiteSpace(options.ConnectionString))
{
_logger.LogWarning("Using Connection String authentication. This is NOT recommended for production. Use App Registration or Managed Identity instead.");
return new QueueClient(options.ConnectionString, options.QueueName);
}
// Valida che QueueServiceUri sia configurato per autenticazione Entra ID
if (options.QueueServiceUri == null)
{
_logger.LogError("QueueServiceUri is required for Entra ID authentication.");
return null;
}
var queueUri = new Uri(options.QueueServiceUri, options.QueueName);
TokenCredential credential;
// Metodo 2: App Registration con Client Secret (raccomandato per service-to-service)
if (options.AuthenticationMethod.Equals("AppRegistration", StringComparison.OrdinalIgnoreCase))
{
if (string.IsNullOrWhiteSpace(options.TenantId) ||
string.IsNullOrWhiteSpace(options.ClientId) ||
string.IsNullOrWhiteSpace(options.ClientSecret))
{
_logger.LogError("TenantId, ClientId, and ClientSecret are required for App Registration authentication.");
return null;
{
private readonly ILogger<AzureQueueReportSink> _logger;
private readonly IOptionsMonitor<SecureBootWatcherOptions> _options;
private readonly AsyncRetryPolicy _retryPolicy;
public AzureQueueReportSink(ILogger<AzureQueueReportSink> logger, IOptionsMonitor<SecureBootWatcherOptions> options)
{
_logger = logger;
_options = options;
_retryPolicy = Policy
.Handle<RequestFailedException>()
.Or<TimeoutException>()
.WaitAndRetryAsync(3, attempt => TimeSpan.FromSeconds(Math.Pow(2, attempt)), (ex, span, attempt, _) =>
{
_logger.LogWarning(ex, "Retrying Azure Queue send attempt {Attempt} after {Delay}.", attempt, span);
});
}
public async Task EmitAsync(SecureBootStatusReport report, CancellationToken cancellationToken)
{
var sinkOptions = _options.CurrentValue.Sinks.AzureQueue;
if (string.IsNullOrWhiteSpace(sinkOptions.QueueName))
{
_logger.LogDebug("Azure Queue sink is disabled because QueueName is not configured.");
return;
}
var queueClient = CreateQueueClient(sinkOptions);
if (queueClient == null)
{
_logger.LogWarning("Azure Queue sink skipped because required configuration is missing.");
return;
}
await queueClient.CreateIfNotExistsAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
var envelope = new SecureBootQueueEnvelope
{
Report = report,
EnqueuedAtUtc = DateTimeOffset.UtcNow
};
var payload = JsonSerializer.Serialize(envelope, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = false
});
await _retryPolicy.ExecuteAsync(async token =>
{
await queueClient.SendMessageAsync(
BinaryData.FromString(payload),
visibilityTimeout: sinkOptions.VisibilityTimeout,
cancellationToken: token).ConfigureAwait(false);
_logger.LogInformation("Secure Boot report enqueued to {QueueName} using {AuthMethod} authentication.",
queueClient.Name, sinkOptions.AuthenticationMethod);
}, cancellationToken).ConfigureAwait(false);
}
private QueueClient? CreateQueueClient(AzureQueueSinkOptions options)
{
try
{
// Metodo 1: Connection String (non raccomandato per produzione)
if (options.AuthenticationMethod.Equals("ConnectionString", StringComparison.OrdinalIgnoreCase) &&
!string.IsNullOrWhiteSpace(options.ConnectionString))
{
_logger.LogWarning("Using Connection String authentication. This is NOT recommended for production. Use App Registration or Managed Identity instead.");
return new QueueClient(options.ConnectionString, options.QueueName);
}
// Valida che QueueServiceUri sia configurato per autenticazione Entra ID
if (options.QueueServiceUri == null)
{
_logger.LogError("QueueServiceUri is required for Entra ID authentication.");
return null;
}
var queueUri = new Uri(options.QueueServiceUri, options.QueueName);
TokenCredential credential;
// Metodo 2: App Registration con Client Secret (raccomandato per service-to-service)
if (options.AuthenticationMethod.Equals("AppRegistration", StringComparison.OrdinalIgnoreCase))
{
if (string.IsNullOrWhiteSpace(options.TenantId) ||
string.IsNullOrWhiteSpace(options.ClientId) ||
string.IsNullOrWhiteSpace(options.ClientSecret))
{
_logger.LogError("TenantId, ClientId, and ClientSecret are required for App Registration authentication.");
return null;

Copilot uses AI. Check for mistakes.
{
try
{
// Metodo 1: Connection String (non raccomandato per produzione)
Copy link

Copilot AI Nov 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment is in Italian. Should be translated to English: 'Method 1: Connection String (not recommended for production)'.

Suggested change
// Metodo 1: Connection String (non raccomandato per produzione)
// Method 1: Connection String (not recommended for production)

Copilot uses AI. Check for mistakes.
return new QueueClient(options.ConnectionString, options.QueueName);
}

// Valida che QueueServiceUri sia configurato per autenticazione Entra ID
Copy link

Copilot AI Nov 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment is in Italian. Should be translated to English: 'Validate that QueueServiceUri is configured for Entra ID authentication'.

Suggested change
// Valida che QueueServiceUri sia configurato per autenticazione Entra ID
// Validate that QueueServiceUri is configured for Entra ID authentication

Copilot uses AI. Check for mistakes.
Comment on lines +146 to +149
catch (Exception ex)
{
_logger.LogDebug(ex, "Failed to read file {Path}", path);
}
Copy link

Copilot AI Nov 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generic catch clause.

Suggested change
catch (Exception ex)
{
_logger.LogDebug(ex, "Failed to read file {Path}", path);
}
catch (IOException ex)
{
_logger.LogDebug(ex, "Failed to read file {Path}", path);
}
catch (UnauthorizedAccessException ex)
{
_logger.LogDebug(ex, "Failed to read file {Path}", path);
}

Copilot uses AI. Check for mistakes.
Comment on lines +250 to +254
catch (Exception ex)
{
_logger.LogError(ex, "Failed to create Azure Queue client with authentication method: {Method}", options.AuthenticationMethod);
return null;
}
Copy link

Copilot AI Nov 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generic catch clause.

Suggested change
catch (Exception ex)
{
_logger.LogError(ex, "Failed to create Azure Queue client with authentication method: {Method}", options.AuthenticationMethod);
return null;
}
catch (Azure.Identity.AuthenticationFailedException ex)
{
_logger.LogError(ex, "Authentication failed while creating Azure Queue client with authentication method: {Method}", options.AuthenticationMethod);
return null;
}
catch (Azure.RequestFailedException ex)
{
_logger.LogError(ex, "Request to Azure Queue failed with authentication method: {Method}", options.AuthenticationMethod);
return null;
}
catch (ArgumentException ex)
{
_logger.LogError(ex, "Invalid argument while creating Azure Queue client with authentication method: {Method}", options.AuthenticationMethod);
return null;
}
catch (InvalidOperationException ex)
{
_logger.LogError(ex, "Invalid operation while creating Azure Queue client with authentication method: {Method}", options.AuthenticationMethod);
return null;
}

Copilot uses AI. Check for mistakes.
Comment on lines +147 to +151
catch (Exception ex)
{
_logger.LogError(ex, "Failed to load certificate from file: {Path}", options.CertificatePath);
return null;
}
Copy link

Copilot AI Nov 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generic catch clause.

Copilot uses AI. Check for mistakes.
Comment on lines +185 to +189
catch (Exception ex)
{
_logger.LogError(ex, "Failed to load certificate from store. Thumbprint: {Thumbprint}", options.CertificateThumbprint);
return null;
}
Copy link

Copilot AI Nov 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generic catch clause.

Copilot uses AI. Check for mistakes.
Comment on lines +103 to +143
catch (Exception ex)
{
lastException = ex;

if (attemptNumber <= maxRetries)
{
// Calculate delay for next retry
var delay = GetCurrentDelay(attemptNumber, retryDelay, useExponentialBackoff);

_logger.LogWarning(
"? Attempt {Attempt}/{MaxRetries} failed for {SinkName}: {ErrorMessage}. Retrying in {Delay}...",
attemptNumber,
maxRetries + 1,
sinkName,
ex.Message,
delay);

// Wait before retry (unless it's the last attempt)
if (attemptNumber <= maxRetries)
{
try
{
await Task.Delay(delay, cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
_logger.LogInformation("Retry cancelled for {SinkName}", sinkName);
break;
}
}
}
else
{
// Log error without full stack trace since we'll try next sink
_logger.LogWarning(
"? All {TotalAttempts} attempts failed for {SinkName}: {ErrorMessage}. Moving to next sink.",
attemptNumber,
sinkName,
lastException?.Message ?? "Unknown error");
}
}
Copy link

Copilot AI Nov 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generic catch clause.

Copilot uses AI. Check for mistakes.
@robgrame robgrame requested a review from Copilot November 7, 2025 12:57
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 31 out of 33 changed files in this pull request and generated 22 comments.

Comment thread SecureBootWatcher.LinuxClient/Sinks/AzureQueueReportSink.cs Outdated
Comment thread SecureBootWatcher.LinuxClient/Sinks/AzureQueueReportSink.cs Outdated
Comment thread SecureBootWatcher.LinuxClient/Sinks/AzureQueueReportSink.cs Outdated
return new QueueClient(queueUri, credential);
}

// Metodo 3: Certificate-based authentication (PI� SICURO - raccomandato per produzione)
Copy link

Copilot AI Nov 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments are written in Italian instead of English. All code comments should be in English for consistency with the rest of the codebase. For example, 'Metodo 1' should be 'Method 1', 'non raccomandato' should be 'not recommended', 'Valida che' should be 'Validate that', 'Opzione A' should be 'Option A', 'Carica certificato' should be 'Load certificate', etc.

Suggested change
// Metodo 3: Certificate-based authentication (PI� SICURO - raccomandato per produzione)
// Method 3: Certificate-based authentication (MORE SECURE - recommended for production)

Copilot uses AI. Check for mistakes.
Comment thread SecureBootWatcher.LinuxClient/Sinks/AzureQueueReportSink.cs Outdated
Comment thread SecureBootWatcher.LinuxClient/Services/LinuxSecureBootCertificateEnumerator.cs Outdated
Comment thread SecureBootWatcher.LinuxClient/Services/SecureBootWatcherService.cs
Comment thread SecureBootWatcher.LinuxClient/Services/LinuxSecureBootCertificateEnumerator.cs Outdated
Comment thread SecureBootWatcher.LinuxClient/Services/LinuxSecureBootCertificateEnumerator.cs Outdated
Comment on lines +366 to +370
catch (Exception ex)
{
_logger.LogDebug(ex, "Failed to parse certificate from {Database}", databaseName);
return null;
}
Copy link

Copilot AI Nov 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generic catch clause.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

@robgrame robgrame requested a review from Copilot November 7, 2025 14:11
robgrame and others added 11 commits November 7, 2025 15:12
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
robgrame and others added 8 commits November 8, 2025 08:29
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@robgrame robgrame requested a review from Copilot November 8, 2025 07:31
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 31 out of 33 changed files in this pull request and generated 10 comments.

Comment thread SecureBootWatcher.LinuxClient/Storage/FileEventCheckpointStore.cs Outdated
Comment thread SecureBootWatcher.LinuxClient/Sinks/FileShareReportSink.cs Outdated
Comment thread SecureBootWatcher.LinuxClient/Sinks/AzureQueueReportSink.cs Outdated
Comment thread SecureBootWatcher.LinuxClient/Services/LinuxEventLogReader.cs
Comment thread SecureBootWatcher.LinuxClient/Sinks/AzureQueueReportSink.cs Outdated
Comment thread SecureBootWatcher.LinuxClient/Services/LinuxEventLogReader.cs Outdated
Comment thread SecureBootWatcher.LinuxClient/Services/LinuxSecureBootCertificateEnumerator.cs Outdated
Comment thread SecureBootWatcher.LinuxClient/Sinks/AzureQueueReportSink.cs Outdated
Comment thread SecureBootWatcher.LinuxClient/Services/ReportBuilder.cs Outdated
robgrame and others added 8 commits November 8, 2025 08:51
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@robgrame robgrame requested a review from Copilot November 8, 2025 07:53
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 31 out of 33 changed files in this pull request and generated 13 comments.

Comment thread SecureBootWatcher.LinuxClient/Sinks/SinkCoordinator.cs
Comment thread SecureBootWatcher.LinuxClient/Sinks/SinkCoordinator.cs
Comment thread SecureBootWatcher.LinuxClient/Program.cs Outdated
Comment thread SecureBootWatcher.LinuxClient/Sinks/AzureQueueReportSink.cs Outdated
Comment thread SecureBootWatcher.LinuxClient/Sinks/AzureQueueReportSink.cs Outdated
Comment thread SecureBootWatcher.LinuxClient/Services/LinuxEventLogReader.cs
Comment thread SecureBootWatcher.LinuxClient/Services/LinuxSecureBootCertificateEnumerator.cs Outdated
Comment thread SecureBootWatcher.LinuxClient/Sinks/AzureQueueReportSink.cs Outdated
Comment thread SecureBootWatcher.LinuxClient/Sinks/AzureQueueReportSink.cs Outdated
Comment thread SecureBootWatcher.LinuxClient/Sinks/AzureQueueReportSink.cs Outdated
robgrame and others added 8 commits November 8, 2025 10:54
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@robgrame robgrame requested a review from Copilot November 8, 2025 10:22
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 31 out of 33 changed files in this pull request and generated 8 comments.

return null;
}

certificate = certificates[0];
Copy link

Copilot AI Nov 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable certificate is not declared in this scope. The code attempts to assign to certificate without declaring it first. This should be declared earlier in the method or the certificate should be used directly within the using block.

Copilot uses AI. Check for mistakes.
return null;
}
}
// Option B: Load certificate from Windows Certificate Store
Copy link

Copilot AI Nov 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment references 'Windows Certificate Store' in the Linux client. While the X509Store API is cross-platform in .NET, this comment is misleading since it suggests Windows-specific functionality. Consider updating to 'Option B: Load certificate from system certificate store' or clarify that this uses the system's certificate store on Linux.

Suggested change
// Option B: Load certificate from Windows Certificate Store
// Option B: Load certificate from system certificate store (cross-platform: Windows, Linux, macOS)

Copilot uses AI. Check for mistakes.
Comment on lines +112 to +113
_logger.LogWarning(
"? Attempt {Attempt}/{MaxRetries} failed for {SinkName}: {ErrorMessage}. Retrying in {Delay}...",
Copy link

Copilot AI Nov 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The log message contains a '?' character that appears to be a placeholder or unintended character. This should likely be removed or replaced with an appropriate emoji/icon if intended.

Copilot uses AI. Check for mistakes.
Comment on lines +137 to +138
_logger.LogWarning(
"? All {TotalAttempts} attempts failed for {SinkName}: {ErrorMessage}. Moving to next sink.",
Copy link

Copilot AI Nov 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The log message contains a '?' character that appears to be a placeholder or unintended character. This should likely be removed or replaced with an appropriate emoji/icon if intended.

Copilot uses AI. Check for mistakes.
var events = await QueryJournalctlAsync(since, cancellationToken).ConfigureAwait(false);
records.AddRange(events);
}
catch (Exception ex)
Copy link

Copilot AI Nov 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generic catch clause.

Suggested change
catch (Exception ex)
catch (Exception ex) when (ex is not OperationCanceledException && ex is not TaskCanceledException)

Copilot uses AI. Check for mistakes.
Comment on lines +266 to +271
catch (Exception ex)
{
_logger.LogError(ex, "Failed to create Azure Queue client with authentication method: {Method}", options.AuthenticationMethod);
return null;
}
}
Copy link

Copilot AI Nov 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generic catch clause.

Suggested change
catch (Exception ex)
{
_logger.LogError(ex, "Failed to create Azure Queue client with authentication method: {Method}", options.AuthenticationMethod);
return null;
}
}
catch (AuthenticationFailedException ex)
{
_logger.LogError(ex, "Authentication failed when creating Azure Queue client with authentication method: {Method}", options.AuthenticationMethod);
return null;
}
catch (RequestFailedException ex)
{
_logger.LogError(ex, "Azure request failed when creating Azure Queue client with authentication method: {Method}", options.AuthenticationMethod);
return null;
}
catch (OperationCanceledException ex)
{
_logger.LogError(ex, "Operation was canceled when creating Azure Queue client with authentication method: {Method}", options.AuthenticationMethod);
return null;
}
// Optionally catch other non-critical exceptions
catch (Exception ex) when (!(ex is OutOfMemoryException) && !(ex is StackOverflowException) && !(ex is ThreadAbortException))
{
_logger.LogError(ex, "Unexpected error when creating Azure Queue client with authentication method: {Method}", options.AuthenticationMethod);
return null;
}
}

Copilot uses AI. Check for mistakes.
Comment on lines +201 to +205
catch (Exception ex)
{
_logger.LogError(ex, "Failed to load certificate from store. Thumbprint: {Thumbprint}", options.CertificateThumbprint);
return null;
}
Copy link

Copilot AI Nov 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generic catch clause.

Suggested change
catch (Exception ex)
{
_logger.LogError(ex, "Failed to load certificate from store. Thumbprint: {Thumbprint}", options.CertificateThumbprint);
return null;
}
catch (CryptographicException ex)
{
_logger.LogError(ex, "Cryptographic error loading certificate from store. Thumbprint: {Thumbprint}", options.CertificateThumbprint);
return null;
}
catch (ArgumentException ex)
{
_logger.LogError(ex, "Argument error loading certificate from store. Thumbprint: {Thumbprint}", options.CertificateThumbprint);
return null;
}
catch (InvalidOperationException ex)
{
_logger.LogError(ex, "Invalid operation loading certificate from store. Thumbprint: {Thumbprint}", options.CertificateThumbprint);
return null;
}

Copilot uses AI. Check for mistakes.
return;
}
catch (Exception ex)
{
Copy link

Copilot AI Nov 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generic catch clause.

Suggested change
{
{
// Rethrow critical exceptions
if (ex is OutOfMemoryException ||
ex is StackOverflowException ||
ex is ThreadAbortException ||
ex is AccessViolationException)
{
throw;
}

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Linux client support (.NET 8)

3 participants