-
Notifications
You must be signed in to change notification settings - Fork 2
Fix SQS Event Source LocalStack Integration #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Add SQSEventSourceResource detection in UseLocalStack() Implement ConfigureSqsEventSourceResource() with surgical annotation insertion Add AWS_ENDPOINT_URL environment variable injection for Lambda Tools Enhance ConstantsTests with AWS class validation for breaking change detection Add comprehensive unit tests for new SQS Event Source configuration Resolves issue #6 - Invalid URL error when Lambda with SQS event source uses LocalStack endpoint BREAKING: This fix requires playground validation before release completion TODO: Test with Lambda playground to validate the fix effectiveness
…mplementation Add comprehensive SQS Event Source testing with analytics flow: - Add Analyzer Lambda to process SQS events (url_created, url_accessed) - Add AnalyticsQueue (SQS) and UrlAnalytics (DynamoDB) to CDK stack - Update UrlShortener and Redirector Lambdas to send analytics events - Demonstrate complete event-driven architecture with LocalStack Simplify SQS Event Source configuration: - Replace surgical annotation insertion with WithEnvironment() extension - Remove complex annotation ordering logic (not needed with Aspire's append behavior) - Update unit tests to properly mock WithAnnotation() callbacks Update documentation: - Add analytics flow architecture diagram to lambda README - Update resource inventory (3 Lambdas, SQS, analytics table) - Add CLI commands for testing analytics functionality - Highlight SQS Event Source demonstration This validates the fix from commit c0005ad and provides a real-world test case for the AWS_ENDPOINT_URL environment variable injection. Closes #6
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.OpenSSF Scorecard
Scanned Files
|
There was a problem hiding this 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 fixes a critical issue where AWS Lambda functions with SQS Event Sources fail to connect to LocalStack due to "Invalid URI" errors. The fix automatically injects the AWS_ENDPOINT_URL environment variable into SQS Event Source resources. Additionally, it includes a comprehensive analytics testing playground with event-driven architecture to validate the fix.
- Fixes SQS Event Source LocalStack integration by adding environment variable injection
- Updates test coverage with new unit tests for the SQS configuration logic
- Adds complete analytics playground with 3 Lambda functions demonstrating real-world SQS Event Source usage
Reviewed Changes
Copilot reviewed 26 out of 26 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
src/Aspire.Hosting.LocalStack/Internal/Constants.cs |
Adds constant for SQS Event Source resource type name |
src/Aspire.Hosting.LocalStack/Internal/LocalStackResourceConfigurator.cs |
Implements SQS Event Source configuration method |
src/Aspire.Hosting.LocalStack/Internal/LocalStackConnectionStringAvailableCallback.cs |
Adds SQS Event Source detection and configuration logic |
src/Aspire.Hosting.LocalStack/LocalStackResourceBuilderExtensions.cs |
Adds SQS Event Source resource detection in UseLocalStack method |
tests/Aspire.Hosting.LocalStack.Unit.Tests/Internal/LocalStackResourceConfiguratorTests.cs |
Comprehensive unit tests for SQS Event Source configuration |
tests/Aspire.Hosting.LocalStack.Unit.Tests/Internal/ConstantsTests.cs |
Validation tests for AWS assembly type existence |
playground/lambda/* |
Complete analytics playground demonstrating SQS Event Source functionality |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
playground/provisioning/LocalStack.Provisioning.Frontend/Handlers/ChatMessageHandler.cs
Show resolved
Hide resolved
…ests
Replace type reference hack with Assembly.Load("Aspire.Hosting.AWS") to
ensure assembly loads consistently across all platforms and configurations.
Fixes test failures on Linux/macOS where AWS types were not found in
Release builds due to compiler optimizations.
Fix artifact name containing invalid forward slash character that caused upload failures. Introduce ARTIFACT_SUFFIX variable using sanitized branch name for artifact naming. Enforce NuGet Semantic Versioning 2.0.0 compliance for all CI builds: - Feature branches: 9.5.0-feature-name.buildnumber - Master CI builds: 9.5.0-ci.buildnumber (explicit pre-release marker) The -ci prefix ensures all automated builds are marked as pre-release, while stable releases remain controlled via manual workflow dispatch. Changes: - Use SAFE_BRANCH for artifact names instead of raw github.head_ref - Add explicit -ci suffix for master builds (was 4-part version) - Export artifact_suffix as step output for reuse - Update build summary to show artifact name and SemVer compliance Fixes GitHub Actions artifact upload error: "The artifact name is not valid: packages-feature/full-release-preparations-29. Contains the following character: Forward slash /"
Sanitize user input before logging to prevent log injection attacks in Redirector and UrlShortener Lambda functions.
Add ITestOutputHelper integration with xUnit logging and verify analytics resources (SQS queue + DynamoDB table) from PR #9. Phase 1 of integration testing improvements: - Configure structured logging with MartinCostello.Logging.XUnit.v3 - Verify AnalyticsQueueUrl and AnalyticsTableName outputs - Add SQS and DynamoDB resource existence checks - Improve test diagnostics with better assertions - Clean up commented code Created integration-tests-roadmap.md for Phase 2 (fixtures) and Phase 3 (e2e). Tests: 2/2 passing ✅
…d test methods BREAKING CHANGE: Deleted monolithic integration test files in favor of structured approach - Replace 2 monolithic test files with 4 focused test classes using IClassFixture<T> - Create LocalStackLambdaFixture and LocalStackCdkFixture for shared AppHost instances - Extract common test helpers to LocalStackTestHelpers (CloudFormation outputs, session creation) - Split large test methods into 12 focused, individual test methods (6 Lambda + 6 CDK) - Dynamically extract AWS region from LocalStack resource configuration (no hardcoding) - Move CloudFormationStackOutputs to dedicated file for better organization - Mark legacy CdkTestCollection as obsolete Benefits: - Better test isolation and clarity - Faster test execution (shared AppHost per collection) - Easier debugging with focused test methods - Dynamic region configuration prevents configuration drift Deleted: - tests/.../Playground/Lambda/LocalStackLambdaHostTests.cs - tests/.../Playground/Provisioning/LocalStackCDKHostTests.cs Relates-to: #6
- Remove flaky SQS message verification test - Simplify HttpClient handler initialization to avoid linter warnings - Adjust Analyzer Lambda test with manual JSON serialization - Reduce wait time in analytics processing test (10s → 1s) - Remove unused SQS imports The SQS-only verification test was removed as it depends on LocalStack emulator features that aren't fully supported in test scenarios. Core functional tests (URL shortening, QR codes, redirects) remain passing. Refs: Phase 3 integration test improvements
- Adjusted the wait time in the analytics processing test from 1 second to 10 seconds to ensure reliable event processing by the Analyzer Lambda. This change addresses potential timing issues in the test, improving the accuracy of the analytics verification.
Add AWS credential environment variables to SQSEventSourceResource to prevent AWS SDK from attempting SSO token refresh when connecting to LocalStack. The AWS Lambda Test Tool's SQS Event Source background service requires valid AWS credentials before making API calls. On Linux systems with AWS SSO profiles, the SDK would attempt to refresh SSO tokens from real AWS endpoints, causing the Lambda emulator to crash before reaching LocalStack. By explicitly setting AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN, and AWS_DEFAULT_REGION from LocalStack's session options, we force the SDK to use basic authentication and skip SSO/IAM role credential chain resolution. Changes: - Set AWS credential env vars in ConfigureSqsEventSourceResource - Use ILocalStackOptions.Session credentials for consistency - Ensures cross-platform compatibility (Windows, macOS, Linux) This completes the SQS Event Source LocalStack integration and resolves authentication failures in CI environments. Fixes: #6 Tested: WSL Linux, Windows, macOS
Updated the HTTP client timeout from 30 seconds to 60 seconds in multiple Lambda functional tests to accommodate longer cold start times. This change aims to enhance test reliability and prevent timeouts during integration testing with LocalStack. Changes: - Increased timeout for API Gateway client and redirect client in various test methods. This adjustment addresses potential timing issues and improves the overall stability of the tests.
…configuration Changes: - Replaced options.Session.AwsSessionToken with options.Session.AwsAccessKey for AWS_SECRET_ACCESS_KEY.
There was a problem hiding this 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 41 out of 41 changed files in this pull request and generated 4 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| var mockExecutableResource = new ExecutableResource("test-sqs-resource", "test-command", "test-workdir"); | ||
| var (options, _, _) = TestDataBuilders.CreateMockLocalStackOptions( | ||
| localStackHost: "test-host", | ||
| edgePort: 9999, | ||
| useSsl: false); | ||
| var mockBuilder = Substitute.For<IResourceBuilder<ExecutableResource>>(); | ||
| mockBuilder.Resource.Returns(mockExecutableResource); | ||
|
|
||
| // Configure the mock to actually add annotations when WithAnnotation is called | ||
| mockBuilder.WithAnnotation(Arg.Do<EnvironmentCallbackAnnotation>(ann => mockExecutableResource.Annotations.Add(ann)), Arg.Any<ResourceAnnotationMutationBehavior>()) | ||
| .Returns(mockBuilder); | ||
|
|
||
| var localStackUrl = new Uri("http://localhost:4566"); | ||
|
|
||
| // Act | ||
| LocalStackResourceConfigurator.ConfigureSqsEventSourceResource(mockBuilder, localStackUrl, options); |
Copilot
AI
Oct 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test setup pattern for mocking WithAnnotation is duplicated across multiple test methods. Consider extracting this common setup into a helper method to reduce code duplication and improve maintainability.
| var awsAssembly = Assembly.Load("Aspire.Hosting.AWS"); | ||
| _ = awsAssembly; // Suppress unused warning |
Copilot
AI
Oct 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The assembly loading in the constructor could fail with FileNotFoundException if the AWS assembly is not available, causing all tests in this class to fail during construction. Consider wrapping this in a try-catch block or moving it to a static constructor with proper error handling.
| var awsAssembly = Assembly.Load("Aspire.Hosting.AWS"); | |
| _ = awsAssembly; // Suppress unused warning | |
| try | |
| { | |
| var awsAssembly = Assembly.Load("Aspire.Hosting.AWS"); | |
| _ = awsAssembly; // Suppress unused warning | |
| } | |
| catch (System.IO.FileNotFoundException) | |
| { | |
| // AWS assembly not found. Tests that require it may fail or should handle this case. | |
| } | |
| catch (System.IO.FileLoadException) | |
| { | |
| // AWS assembly could not be loaded. Tests that require it may fail or should handle this case. | |
| } | |
| catch (BadImageFormatException) | |
| { | |
| // AWS assembly is not a valid assembly. Tests that require it may fail or should handle this case. | |
| } |
| catch (Exception ex) | ||
| { | ||
| // Log but don't throw - analytics shouldn't break URL creation | ||
| lambdaContext.Logger.LogWarning($"Failed to send analytics event: {ex.Message}"); |
Copilot
AI
Oct 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logging the exception message directly could potentially expose sensitive information. Consider logging a sanitized message or using structured logging with appropriate filtering for production environments.
| lambdaContext.Logger.LogWarning($"Failed to send analytics event: {ex.Message}"); | |
| lambdaContext.Logger.LogWarning("Failed to send analytics event."); |
| catch (Exception ex) | ||
| { | ||
| // Log but don't throw - analytics shouldn't break redirects | ||
| lambdaContext.Logger.LogWarning($"Failed to send analytics event: {ex.Message}"); |
Copilot
AI
Oct 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same security concern as in UrlShortener - logging exception messages directly could expose sensitive information. Consider using structured logging or sanitizing the message.
| lambdaContext.Logger.LogWarning($"Failed to send analytics event: {ex.Message}"); | |
| lambdaContext.Logger.LogWarning($"Failed to send analytics event for slug '{slug}'. Exception type: {ex.GetType().Name}"); |
- Replace Gist-based badge system with BadgeSmith REST API - Implement HMAC-SHA256 authentication for secure badge updates - Add branch-specific badge support (master and feature branches) - Update CI/CD workflow to post test results via authenticated API - Refactor update-test-badge action to extract owner/repo/branch from context - Update README badges to use new BadgeSmith endpoints - Add Windows and macOS test badges to README - Remove Release Candidate status and warnings - Add comprehensive v9.5.0 CHANGELOG entry - Document SQS Event Source bug fix (#6, #9) - Document eager service loading feature (#7, #8) - Update LocalStack container to 4.9.1 - Update Aspire.Hosting to 9.5.0 - Credit contributors: @slang25 (eager loading), @Blind-Striker (bug fixes, infra)
What does this PR do?
This PR fixes the critical issue where AWS Lambda functions with SQS Event Sources fail to connect to LocalStack, throwing "Invalid URI" errors. The fix automatically injects the
AWS_ENDPOINT_URLenvironment variable into SQS Event Source resources, enabling the AWS Lambda Tools to properly connect to LocalStack's SQS service.Additionally, this PR includes a complete testing playground with an analytics-driven architecture to validate the fix in a real-world scenario.
Related Issue(s):
🔄 Type of Change
🎯 Aspire Compatibility
🧪 Testing
How has this been tested?
ConfigureSqsEventSourceResourcetestsWithEnvironment()patternUseLocalStack())WithReference()) - Not applicable for this fixTest Environment:
📚 Documentation
playground/lambda/README.mdwith analytics architectureplayground/README.mdwith SQS mentionLocalStack.Lambda.AnalyzerprojectUrlShortenerandRedirectorwith analytics✅ Code Quality Checklist
🔍 Additional Notes
Breaking Changes:
None. This is a backward-compatible fix that enhances existing functionality.
Performance Impact:
Minimal. The fix only adds environment variable injection during resource configuration (one-time setup cost). No runtime performance impact.
Dependencies:
AWSSDK.SQSto Redirector and UrlShortener Lambda projects (for analytics testing)🎯 Reviewer Focus Areas
Please pay special attention to:
WithEnvironment()extension pattern🏗️ Architecture Overview
The Problem
When using
WithSQSEventSource()with LocalStack, the AWS Lambda Tools process tries to parse the LocalStack URL (http://localhost.localstack.cloud:4566) as an AWS region, causing an "Invalid URI" error.The Solution
Automatically inject
AWS_ENDPOINT_URLenvironment variable into SQS Event Source resources, instructing Lambda Tools to use the LocalStack endpoint instead of AWS.Implementation Details
1. Detection (LocalStackResourceConfigurator.cs)
2. Configuration (Simplified Approach)
3. Validation (ConstantsTests.cs)
SQSEventSourceResourcetype exists in Aspire.Hosting.AWSAnalytics Testing Playground
New Resources:
Event Flow:
📸 Screenshots/Examples
Using the Analytics Flow
Code Example in AppHost
🎯 Validation Criteria
By submitting this pull request, I confirm that:
Note
Detects SQS Event Source resources and injects AWS_ENDPOINT_URL for LocalStack, adds an end-to-end analytics playground (SQS+DynamoDB) and updates versions/CI to Aspire 9.5 with SemVer2 artifacts.
SQSEventSourceResourceand injectsAWS_ENDPOINT_URLto route SDK calls to LocalStack.UseLocalStack/connection callback to handleExecutableResourceSQS event sources; addsConstants.SQSEventSourceResource.9.5.0.LocalStack.Lambda.Analyzer(SQS-triggered) and wires SQS event source in AppHost.AnalyticsQueue(SQS) andUrlAnalytics(DynamoDB) outputs.UrlShortener/Redirectorto emit analytics to SQS; analyzer persists to DynamoDB.Written by Cursor Bugbot for commit 4915669. This will update automatically on new commits. Configure here.