Skip to content

Release v2.0.0 with AWS cloud support.#7

Open
NinjaRocks wants to merge 7 commits intomasterfrom
release/v2.0.0-aws
Open

Release v2.0.0 with AWS cloud support.#7
NinjaRocks wants to merge 7 commits intomasterfrom
release/v2.0.0-aws

Conversation

@NinjaRocks
Copy link
Member

SourceFlow.Net v2.0.0 - Changelog

Release Date: TBC
Status: In Development

Note: This release includes AWS cloud integration support. Azure cloud integration will be available in a future release.

🎉 Major Changes

Cloud Core Consolidation

The SourceFlow.Cloud.Core project has been consolidated into the main SourceFlow package. This architectural change simplifies the dependency structure and reduces the number of separate packages required for cloud integration.

Benefits:

  • ✅ Simplified package management (one less NuGet package)
  • ✅ Reduced build complexity
  • ✅ Improved discoverability (cloud functionality is part of core)
  • ✅ Better performance (eliminates one layer of assembly loading)
  • ✅ Easier testing (no intermediate package dependencies)

✨ New Features

Integrated Cloud Functionality

The following components are now part of the core SourceFlow package:

Configuration

  • BusConfiguration - Fluent API for routing configuration
  • IBusBootstrapConfiguration - Bootstrapper integration
  • ICommandRoutingConfiguration - Command routing abstraction
  • IEventRoutingConfiguration - Event routing abstraction
  • IIdempotencyService - Duplicate message detection
  • InMemoryIdempotencyService - Default implementation
  • IdempotencyConfigurationBuilder - Fluent API for idempotency configuration

Resilience

  • ICircuitBreaker - Circuit breaker pattern interface
  • CircuitBreaker - Implementation with state management
  • CircuitBreakerOptions - Configuration options
  • CircuitBreakerOpenException - Exception for open circuits
  • CircuitBreakerStateChangedEventArgs - State transition events

Security

  • IMessageEncryption - Message encryption abstraction
  • SensitiveDataAttribute - Marks properties for encryption
  • SensitiveDataMasker - Automatic log masking
  • EncryptionOptions - Encryption configuration

Dead Letter Processing

  • IDeadLetterProcessor - Failed message handling
  • IDeadLetterStore - Failed message persistence
  • DeadLetterRecord - Failed message model
  • InMemoryDeadLetterStore - Default implementation

Observability

  • CloudActivitySource - OpenTelemetry activity source
  • CloudMetrics - Standard cloud metrics
  • CloudTelemetry - Centralized telemetry

Serialization

  • PolymorphicJsonConverter - Handles inheritance hierarchies

Idempotency Configuration Builder

New fluent API for configuring idempotency services:

// Entity Framework-based (multi-instance)
var idempotencyBuilder = new IdempotencyConfigurationBuilder()
    .UseEFIdempotency(connectionString, cleanupIntervalMinutes: 60);

// In-memory (single-instance)
var idempotencyBuilder = new IdempotencyConfigurationBuilder()
    .UseInMemory();

// Custom implementation
var idempotencyBuilder = new IdempotencyConfigurationBuilder()
    .UseCustom<MyCustomIdempotencyService>();

// Apply configuration
idempotencyBuilder.Build(services);

Builder Methods:

  • UseEFIdempotency(connectionString, cleanupIntervalMinutes) - Entity Framework-based (requires SourceFlow.Stores.EntityFramework package)
  • UseInMemory() - In-memory implementation
  • UseCustom<TImplementation>() - Custom implementation by type
  • UseCustom(factory) - Custom implementation with factory function

Enhanced AWS Integration

AWS cloud extension now supports explicit idempotency configuration:

services.UseSourceFlowAws(
    options => { options.Region = RegionEndpoint.USEast1; },
    bus => bus.Send.Command<CreateOrderCommand>(q => q.Queue("orders.fifo")),
    configureIdempotency: services =>
    {
        services.AddSourceFlowIdempotency(connectionString);
    });

📚 Documentation Updates

New Documentation

Updated Documentation

🐛 Bug Fixes

  • None (this is a major architectural release)

🔧 Internal Changes

Project Structure

  • Consolidated src/SourceFlow.Cloud.Core/ into src/SourceFlow/Cloud/
  • Simplified dependency graph for cloud extensions
  • Reduced NuGet package count

Build System

  • Updated project references to remove Cloud.Core dependency
  • Simplified build pipeline
  • Reduced compilation time

📦 Package Dependencies

SourceFlow v2.0.0

  • No new dependencies added
  • Cloud functionality now integrated

SourceFlow.Cloud.AWS v2.0.0

  • Depends on: SourceFlow >= 2.0.0
  • Removed: SourceFlow.Cloud.Core dependency

🚀 Upgrade Path

For AWS Extension Users

If you're using the AWS cloud extension, no code changes are required. The consolidation is transparent to consumers of the cloud package.

📝 Notes

  • This is a major version release due to breaking namespace changes
  • The consolidation improves the overall architecture and developer experience
  • All functionality from Cloud.Core is preserved in the main SourceFlow package
  • AWS cloud extension remains a separate package with simplified dependencies
  • Azure cloud integration will be available in a future release

🔗 Related Documentation


Version: 2.0.0
Date: TBC
Status: In Development


// Log with masked sensitive data
_logger.LogInformation("Command dispatched to AWS SQS: {CommandType} -> {Queue}, Duration: {Duration}ms, Command: {Command}",
commandType, queueUrl, sw.ElapsedMilliseconds, _dataMasker.Mask(command));

Check warning

Code scanning / CodeQL

Exposure of private information Medium

Private data returned by
call to method MaskCreditCard
is written to an external location.
Private data returned by
call to method MaskEmail
is written to an external location.

Copilot Autofix

AI 2 days ago

At a high level, the fix is to ensure that SensitiveDataMasker always returns safely masked (non-sensitive) representations of sensitive fields, even for malformed or unexpected input, so that what gets logged in _dataMasker.Mask(command) can be treated as non-private. CodeQL is flagging calls like MaskCreditCard and MaskEmail as if they were propagating sensitive information; we need to make these functions strictly redacting/obfuscating so that the returned strings can no longer be considered private data.

Best single change without altering existing behavior meaningfully: harden MaskCreditCard and MaskEmail implementations so that they:

  • Never return the full original value or any substring that could reasonably be considered sensitive (for example, email local part, most digits of a card).
  • For credit cards, only keep a minimal, industry-typical non-sensitive fragment, such as the last 4 digits, masking everything else, and handle short or invalid inputs by masking entirely.
  • For emails, mask the local part fully or all but the first and/or last character, and optionally partially mask the domain, again handling unusual formats by full redaction.
  • Optionally, ensure that other sensitive types (SSN, phone, etc.) follow a similar pattern to avoid future alerts, but the specific CodeQL path here focuses on credit cards and emails.

The use site in AwsSqsCommandDispatcherEnhanced does not need to change: it already uses _dataMasker.Mask(command) as intended. All edits will therefore be in src/SourceFlow/Cloud/Security/SensitiveDataMasker.cs around the masking helper methods, adding or adjusting the bodies of MaskCreditCard and MaskEmail (and, if they are not yet implemented in the shown snippet, inserting safe implementations for them).

No new external dependencies are needed; masking can be implemented using basic string operations and Regex from System.Text.RegularExpressions, which is already imported.

Suggested changeset 1
src/SourceFlow/Cloud/Security/SensitiveDataMasker.cs
Outside changed files

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/SourceFlow/Cloud/Security/SensitiveDataMasker.cs b/src/SourceFlow/Cloud/Security/SensitiveDataMasker.cs
--- a/src/SourceFlow/Cloud/Security/SensitiveDataMasker.cs
+++ b/src/SourceFlow/Cloud/Security/SensitiveDataMasker.cs
@@ -101,6 +101,12 @@
 
     private string MaskValue(string value, SensitiveDataType type)
     {
+        // Normalize nulls
+        if (value == null)
+        {
+            return "***REDACTED***";
+        }
+
         return type switch
         {
             SensitiveDataType.CreditCard => MaskCreditCard(value),
@@ -115,8 +121,103 @@
         };
     }
 
+    /// <summary>
+    /// Masks a credit card number, preserving at most the last 4 digits.
+    /// All other characters are replaced with '*'. Non-digit characters are removed before masking.
+    /// If there are fewer than 4 digits, all digits are masked.
+    /// </summary>
     private string MaskCreditCard(string value)
     {
+        if (string.IsNullOrWhiteSpace(value))
+        {
+            return "***REDACTED***";
+        }
+
+        // Keep digits only
+        var digits = new string(value.Where(char.IsDigit).ToArray());
+
+        if (digits.Length == 0)
+        {
+            return "***REDACTED***";
+        }
+
+        const int visible = 4;
+        if (digits.Length <= visible)
+        {
+            // Too short to safely show any part of the number
+            return new string('*', digits.Length);
+        }
+
+        var maskedLength = digits.Length - visible;
+        var visiblePart = digits.Substring(digits.Length - visible, visible);
+
+        // Return a normalized masked representation that never exposes full PAN
+        return new string('*', maskedLength) + visiblePart;
+    }
+
+    /// <summary>
+    /// Masks an email address. The local part is fully masked except possibly the first character.
+    /// The domain is preserved but can be partially masked for safety.
+    /// </summary>
+    private string MaskEmail(string value)
+    {
+        if (string.IsNullOrWhiteSpace(value))
+        {
+            return "***REDACTED***";
+        }
+
+        var parts = value.Split('@');
+        if (parts.Length != 2)
+        {
+            // Not a valid email format; avoid leaking arbitrary identifier
+            return "***REDACTED***";
+        }
+
+        var local = parts[0];
+        var domain = parts[1];
+
+        if (string.IsNullOrEmpty(local))
+        {
+            return "***REDACTED***";
+        }
+
+        // Keep at most the first character of the local part, mask the rest
+        var firstChar = local[0];
+        var maskedLocal = firstChar + new string('*', Math.Max(0, local.Length - 1));
+
+        // Optionally, lightly mask the domain by preserving only TLD and first label character(s)
+        var domainParts = domain.Split('.');
+        if (domainParts.Length >= 2)
+        {
+            var tld = domainParts[^1];
+            var main = domainParts[0];
+            var maskedMain = main.Length > 1
+                ? main[0] + new string('*', main.Length - 1)
+                : "*";
+
+            var middle = domainParts.Length > 2
+                ? string.Join(".", domainParts.Skip(1).Take(domainParts.Length - 2).Select(_ => "*"))
+                : string.Empty;
+
+            var rebuilt = middle.Length > 0
+                ? $"{maskedMain}.{middle}.{tld}"
+                : $"{maskedMain}.{tld}";
+
+            return $"{maskedLocal}@{rebuilt}";
+        }
+
+        // Domain without dots (unusual) - mask all but first char
+        var maskedDomain = domain.Length > 1
+            ? domain[0] + new string('*', domain.Length - 1)
+            : "*";
+
+        return $"{maskedLocal}@{maskedDomain}";
+    }
+
+    // Other masking helpers (MaskPhoneNumber, MaskSSN, etc.) remain unchanged
+
+    private string MaskCreditCard(string value)
+    {
         // Show last 4 digits: ************1234
         var digits = Regex.Replace(value, @"\D", "");
         if (digits.Length >= 4)
EOF
Copilot is powered by AI and may make mistakes. Always verify output.
_logger.LogInformation(
"Command processed from SQS: {CommandType} -> {Queue}, Duration: {Duration}ms, MessageId: {MessageId}, Command: {Command}",
commandTypeName, queueUrl, sw.ElapsedMilliseconds, message.MessageId,
_dataMasker.Mask(command));

Check warning

Code scanning / CodeQL

Exposure of private information Medium

Private data returned by
call to method MaskCreditCard
is written to an external location.
Private data returned by
call to method MaskEmail
is written to an external location.

Copilot Autofix

AI 2 days ago

General approach: ensure that data classified as highly sensitive (credit cards, emails, SSNs, passwords, API keys, etc.) is either (a) not logged at all, or (b) logged only in a heavily redacted, non-identifying form that the security policy and tools treat as non-sensitive. Since the issue is reported on the result of MaskCreditCard/MaskEmail flowing into the logger, the best fix is to strengthen the masking so that its output is no longer considered private (for example, returning a constant token for such fields), while keeping the overall logging behavior (structure, presence of fields) intact.

Concretely, in SensitiveDataMasker.MaskValue we can change the behavior for the most sensitive types so that they do not leak any part of the original value. Right now, SensitiveDataType.CreditCard and SensitiveDataType.Email route to MaskCreditCard(value) and MaskEmail(value). CodeQL treats these as potential sources of private data. To fix this without touching the rest of the system:

  • Modify MaskValue so that for SensitiveDataType.CreditCard and SensitiveDataType.Email we return a generic redaction string such as "***REDACTED***" (or a similarly safe constant) instead of calling the specialized masking functions. This makes it impossible for actual card numbers or email addresses to appear in logs.
  • Optionally leave the specific masking helpers (MaskCreditCard, MaskEmail) in place for other potential uses, but they will no longer be part of the logging path that CodeQL has identified.
  • No change is needed in AwsSqsCommandListenerEnhanced because it already uses _dataMasker.Mask(command) when logging; once the masking is made fully redacting for these types, the logger will only receive non-sensitive tokens.

This change is localized to src/SourceFlow/Cloud/Security/SensitiveDataMasker.cs inside the MaskValue method. No new imports or helper methods are required.

Suggested changeset 1
src/SourceFlow/Cloud/Security/SensitiveDataMasker.cs
Outside changed files

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/SourceFlow/Cloud/Security/SensitiveDataMasker.cs b/src/SourceFlow/Cloud/Security/SensitiveDataMasker.cs
--- a/src/SourceFlow/Cloud/Security/SensitiveDataMasker.cs
+++ b/src/SourceFlow/Cloud/Security/SensitiveDataMasker.cs
@@ -103,14 +103,15 @@
     {
         return type switch
         {
-            SensitiveDataType.CreditCard => MaskCreditCard(value),
-            SensitiveDataType.Email => MaskEmail(value),
+            // For highly sensitive data, do not log any part of the original value
+            SensitiveDataType.CreditCard => "***REDACTED***",
+            SensitiveDataType.Email => "***REDACTED***",
             SensitiveDataType.PhoneNumber => MaskPhoneNumber(value),
-            SensitiveDataType.SSN => MaskSSN(value),
+            SensitiveDataType.SSN => "***REDACTED***",
             SensitiveDataType.PersonalName => MaskPersonalName(value),
             SensitiveDataType.IPAddress => MaskIPAddress(value),
             SensitiveDataType.Password => "********",
-            SensitiveDataType.ApiKey => MaskApiKey(value),
+            SensitiveDataType.ApiKey => "***REDACTED***",
             _ => "***REDACTED***"
         };
     }
EOF
@@ -103,14 +103,15 @@
{
return type switch
{
SensitiveDataType.CreditCard => MaskCreditCard(value),
SensitiveDataType.Email => MaskEmail(value),
// For highly sensitive data, do not log any part of the original value
SensitiveDataType.CreditCard => "***REDACTED***",
SensitiveDataType.Email => "***REDACTED***",
SensitiveDataType.PhoneNumber => MaskPhoneNumber(value),
SensitiveDataType.SSN => MaskSSN(value),
SensitiveDataType.SSN => "***REDACTED***",
SensitiveDataType.PersonalName => MaskPersonalName(value),
SensitiveDataType.IPAddress => MaskIPAddress(value),
SensitiveDataType.Password => "********",
SensitiveDataType.ApiKey => MaskApiKey(value),
SensitiveDataType.ApiKey => "***REDACTED***",
_ => "***REDACTED***"
};
}
Copilot is powered by AI and may make mistakes. Always verify output.
// Log with masked sensitive data
_logger.LogInformation(
"Event published to AWS SNS: {EventType} -> {Topic}, Duration: {Duration}ms, Event: {Event}",
eventType, topicArn, sw.ElapsedMilliseconds, _dataMasker.Mask(@event));

Check warning

Code scanning / CodeQL

Exposure of private information Medium

Private data returned by
call to method MaskCreditCard
is written to an external location.
Private data returned by
call to method MaskEmail
is written to an external location.

Copilot Autofix

AI 2 days ago

General approach: Strengthen the masking implementation so that any value marked as sensitive is fully redacted or irreversibly masked, ensuring that data written to logs no longer qualifies as private information. This way, calls to _dataMasker.Mask(@event) cannot propagate sensitive data to external locations, satisfying both security requirements and the static analysis.

Best concrete fix in this context: Update SensitiveDataMasker.MaskValue’s helper methods (like MaskCreditCard, MaskEmail) so that they return a fully redacted token irrespective of the input value, or at least do not preserve sensitive segments. Since CodeQL points specifically to MaskCreditCard and MaskEmail, we can adjust these to return constant placeholders (for example, "****REDACTED-CARD****" and "****REDACTED-EMAIL****"). This guarantees that even if original values are highly sensitive, the logged output is no longer private data. The rest of the flow in AwsSnsEventDispatcherEnhanced remains unchanged, as it already uses _dataMasker.Mask(@event) and is conceptually correct.

Where and how to change: In src/SourceFlow/Cloud/Security/SensitiveDataMasker.cs, within the SensitiveDataMasker class, add or modify the private methods MaskCreditCard and MaskEmail (and optionally other Mask* helpers) so that they return constant or fully redacted strings, not derived data that could be considered private. We must keep the public API the same (Mask(object? obj) and MaskValue) and avoid changing call sites. No changes are required in AwsSnsEventDispatcherEnhanced.cs, since it already relies on the masker for safe logging.

Needed elements: We only need to (re)define the private helper methods (no new imports or external libraries). The method signatures should match what MaskValue expects: private string MaskCreditCard(string value) and private string MaskEmail(string value) etc., implemented with simple string constants or very aggressive redaction.


Suggested changeset 1
src/SourceFlow/Cloud/Security/SensitiveDataMasker.cs
Outside changed files

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/SourceFlow/Cloud/Security/SensitiveDataMasker.cs b/src/SourceFlow/Cloud/Security/SensitiveDataMasker.cs
--- a/src/SourceFlow/Cloud/Security/SensitiveDataMasker.cs
+++ b/src/SourceFlow/Cloud/Security/SensitiveDataMasker.cs
@@ -115,8 +115,24 @@
         };
     }
 
+    // NOTE: The following masking helpers are intentionally fully redacting.
+    // They do not preserve any part of the original sensitive value, so that
+    // the output can be safely written to logs and other external sinks.
+
     private string MaskCreditCard(string value)
     {
+        // Do not log any portion of the card number; return a constant token.
+        return "***REDACTED-CREDIT-CARD***";
+    }
+
+    private string MaskEmail(string value)
+    {
+        // Do not log any portion of the email address; return a constant token.
+        return "***REDACTED-EMAIL***";
+    }
+
+    private string MaskCreditCard(string value)
+    {
         // Show last 4 digits: ************1234
         var digits = Regex.Replace(value, @"\D", "");
         if (digits.Length >= 4)
EOF
@@ -115,8 +115,24 @@
};
}

// NOTE: The following masking helpers are intentionally fully redacting.
// They do not preserve any part of the original sensitive value, so that
// the output can be safely written to logs and other external sinks.

private string MaskCreditCard(string value)
{
// Do not log any portion of the card number; return a constant token.
return "***REDACTED-CREDIT-CARD***";
}

private string MaskEmail(string value)
{
// Do not log any portion of the email address; return a constant token.
return "***REDACTED-EMAIL***";
}

private string MaskCreditCard(string value)
{
// Show last 4 digits: ************1234
var digits = Regex.Replace(value, @"\D", "");
if (digits.Length >= 4)
Copilot is powered by AI and may make mistakes. Always verify output.
_logger.LogInformation(
"Event processed from SNS: {EventType} -> {Queue}, Duration: {Duration}ms, MessageId: {MessageId}, Event: {Event}",
eventTypeName, queueUrl, sw.ElapsedMilliseconds, message.MessageId,
_dataMasker.Mask(@event));

Check warning

Code scanning / CodeQL

Exposure of private information Medium

Private data returned by
call to method MaskCreditCard
is written to an external location.
Private data returned by
call to method MaskEmail
is written to an external location.

Copilot Autofix

AI 2 days ago

In general, the fix is to avoid writing potentially sensitive data (even after masking) to external logs at normal log levels. Instead, only log non‑sensitive metadata (event type, queue name, message ID, duration, maybe a correlation ID), and omit or heavily summarize the event payload. If developers still need full masked payloads for debugging, that can be done at a higher log level (e.g., LogDebug/LogTrace) and gated behind configuration, but that goes beyond the minimal change requested.

Concretely, in AwsSnsEventListenerEnhanced.cs, we will change the success log statement at lines 316–319 so that it no longer logs the {Event} payload argument at all. The message template will be updated to remove the Event: {Event} placeholder, and the argument _dataMasker.Mask(@event) will be removed. This preserves all existing behavior of the listener (processing, metrics, idempotency, deletion, telemetry) and only reduces the amount of data written to logs. No changes are needed in SensitiveDataMasker.cs for this particular CodeQL alert; the issue arises from logging, not from the masking implementation itself.

Suggested changeset 1
src/SourceFlow.Cloud.AWS/Messaging/Events/AwsSnsEventListenerEnhanced.cs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/SourceFlow.Cloud.AWS/Messaging/Events/AwsSnsEventListenerEnhanced.cs b/src/SourceFlow.Cloud.AWS/Messaging/Events/AwsSnsEventListenerEnhanced.cs
--- a/src/SourceFlow.Cloud.AWS/Messaging/Events/AwsSnsEventListenerEnhanced.cs
+++ b/src/SourceFlow.Cloud.AWS/Messaging/Events/AwsSnsEventListenerEnhanced.cs
@@ -312,11 +312,10 @@
             _cloudTelemetry.RecordSuccess(activity, sw.ElapsedMilliseconds);
             _cloudMetrics.RecordEventReceived(eventTypeName, queueUrl, "aws");
 
-            // 15. Log with masked sensitive data
+            // 15. Log success without including event payload to avoid exposing sensitive data
             _logger.LogInformation(
-                "Event processed from SNS: {EventType} -> {Queue}, Duration: {Duration}ms, MessageId: {MessageId}, Event: {Event}",
-                eventTypeName, queueUrl, sw.ElapsedMilliseconds, message.MessageId,
-                _dataMasker.Mask(@event));
+                "Event processed from SNS: {EventType} -> {Queue}, Duration: {Duration}ms, MessageId: {MessageId}",
+                eventTypeName, queueUrl, sw.ElapsedMilliseconds, message.MessageId);
         }
         catch (Exception ex)
         {
EOF
@@ -312,11 +312,10 @@
_cloudTelemetry.RecordSuccess(activity, sw.ElapsedMilliseconds);
_cloudMetrics.RecordEventReceived(eventTypeName, queueUrl, "aws");

// 15. Log with masked sensitive data
// 15. Log success without including event payload to avoid exposing sensitive data
_logger.LogInformation(
"Event processed from SNS: {EventType} -> {Queue}, Duration: {Duration}ms, MessageId: {MessageId}, Event: {Event}",
eventTypeName, queueUrl, sw.ElapsedMilliseconds, message.MessageId,
_dataMasker.Mask(@event));
"Event processed from SNS: {EventType} -> {Queue}, Duration: {Duration}ms, MessageId: {MessageId}",
eventTypeName, queueUrl, sw.ElapsedMilliseconds, message.MessageId);
}
catch (Exception ex)
{
Copilot is powered by AI and may make mistakes. Always verify output.
var masker = new SensitiveDataMasker();
var masked = masker.Mask(testData);

_logger.LogInformation("Masked data: {MaskedData}", masked);

Check warning

Code scanning / CodeQL

Exposure of private information Medium test

Private data returned by
call to method MaskCreditCard
is written to an external location.
Private data returned by
call to method MaskEmail
is written to an external location.

Copilot Autofix

AI 2 days ago

In general, to fix exposure-of-private-information issues, you either: (a) avoid sending even masked/partially-masked sensitive content to external sinks, or (b) ensure that anything logged is fully non-sensitive (for example, only log that masking succeeded, or log high-level metadata). Here the only problematic action is the test logging the entire masked JSON-like string to the console.

The best fix that preserves existing test behavior is: keep computing masked and keep the assertions on its content, but stop logging masked itself. Instead, you can either remove the log line entirely or replace it with a generic message that does not include the masked data. This leaves functionality (encryption and masking semantics, and the test’s assertions) unchanged while removing the sensitive-sink dataflow that CodeQL flags.

Concretely, in tests/SourceFlow.Cloud.AWS.Tests/Integration/KmsSecurityAndPerformanceTests.cs, in the SensitiveDataMasking_WithCreditCardAttribute_ShouldMaskInLogs test method, change line 81 from logging masked to either a log line that does not include masked data, or remove it. No changes are needed in SensitiveDataMasker itself because it is correctly performing its job; the issue is only that the test writes its output to an external sink. No new imports or helpers are required.

Suggested changeset 1
tests/SourceFlow.Cloud.AWS.Tests/Integration/KmsSecurityAndPerformanceTests.cs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/tests/SourceFlow.Cloud.AWS.Tests/Integration/KmsSecurityAndPerformanceTests.cs b/tests/SourceFlow.Cloud.AWS.Tests/Integration/KmsSecurityAndPerformanceTests.cs
--- a/tests/SourceFlow.Cloud.AWS.Tests/Integration/KmsSecurityAndPerformanceTests.cs
+++ b/tests/SourceFlow.Cloud.AWS.Tests/Integration/KmsSecurityAndPerformanceTests.cs
@@ -78,7 +78,7 @@
         var masker = new SensitiveDataMasker();
         var masked = masker.Mask(testData);
         
-        _logger.LogInformation("Masked data: {MaskedData}", masked);
+        // Note: Do not log masked data to avoid exposing sensitive information in logs.
         
         // Verify masked output doesn't contain full sensitive values
         Assert.DoesNotContain("4532-1234-5678-9010", masked);
EOF
@@ -78,7 +78,7 @@
var masker = new SensitiveDataMasker();
var masked = masker.Mask(testData);

_logger.LogInformation("Masked data: {MaskedData}", masked);
// Note: Do not log masked data to avoid exposing sensitive information in logs.

// Verify masked output doesn't contain full sensitive values
Assert.DoesNotContain("4532-1234-5678-9010", masked);
Copilot is powered by AI and may make mistakes. Always verify output.
Assert.DoesNotContain("MyP@ssw0rd!", masked);
Assert.DoesNotContain("pk_live_abcdefghijklmnopqrstuvwxyz123456", masked);

_logger.LogInformation("Comprehensive masked data: {MaskedData}", masked);

Check warning

Code scanning / CodeQL

Exposure of private information Medium test

Private data returned by
call to method MaskCreditCard
is written to an external location.
Private data returned by
call to method MaskEmail
is written to an external location.

Copilot Autofix

AI 2 days ago

Copilot could not generate an autofix suggestion

Copilot could not generate an autofix suggestion for this alert. Try pushing a new commit or if the problem persists contact support.

Major release with AWS cloud integration, CI/CD enhancements, and comprehensive testing improvements.

## AWS Cloud Integration
- Add AWS SQS/SNS integration for distributed command and event processing
- Implement LocalStack support for local AWS service emulation
- Add comprehensive AWS integration tests with property-based testing
- Fix LocalStack connectivity and authentication in CI environments
- Add external LocalStack detection to prevent container conflicts

## CI/CD Improvements
- Configure LocalStack as GitHub Actions service for integration tests
- Add NuGet cache clearing to prevent stale package metadata issues
- Exclude integration and security tests from CI (run unit tests only)
- Add comprehensive GitHub Actions setup documentation
- Fix GitVersion configuration for release branches
- Update workflows with paths-ignore for documentation changes

## Testing Enhancements
- Add LocalStack timeout and connectivity diagnostics
- Implement property-based tests for AWS service equivalence
- Add dead letter queue processing tests
- Fix SQS queue attribute names and DLQ test timing
- Add CI-optimized LocalStack configuration with extended timeouts

## Documentation
- Add GitHub Actions setup guide with troubleshooting
- Update cloud integration testing documentation
- Add AWS cloud architecture documentation
- Update README with new logo images

## Bug Fixes
- Fix .NET Standard 2.1 compatibility with GlobalUsings.cs
- Fix AWS client endpoint configuration for LocalStack
- Fix IAM enforcement in LocalStack service container
- Fix compilation errors in AwsTestConfiguration

## Breaking Changes
- Cloud.Core functionality consolidated into main SourceFlow package (v2.0.0)
- Namespace changes: SourceFlow.Cloud.Core.* → SourceFlow.Cloud.*

Related specs:
- .kiro/specs/v2-0-0-release-preparation/
- .kiro/specs/github-actions-localstack-timeout-fix/
- .kiro/specs/github-actions-ci-configuration-fix/
@NinjaRocks NinjaRocks force-pushed the release/v2.0.0-aws branch from abb7ad7 to 3db7487 Compare March 7, 2026 22:13
- Release branches now generate pre-release packages with -beta suffix
- Example: 2.0.0-beta.1 instead of 2.0.0
- Prevents accidental stable release publication from release branches
- Final stable releases still triggered by 'release-packages' tag
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.

1 participant