diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index f580012..e92e947 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -9,12 +9,12 @@ We welcome contributions of all kinds - from bug reports and feature requests to - 🐛 **Found a bug?** → [Create an Issue](https://github.com/localstack-dotnet/localstack-dotnet-client/issues/new) - 💡 **Have an idea?** → [Start a Discussion](https://github.com/localstack-dotnet/localstack-dotnet-client/discussions) - ❓ **Need help?** → [Q&A Discussions](https://github.com/localstack-dotnet/localstack-dotnet-client/discussions/categories/q-a) -- 🚹 **Security issue?** → See our [Security Policy](.github/SECURITY.md) +- 🚹 **Security issue?** → See our [Security Policy](SECURITY.md) - 🔧 **Ready to code?** → [Submit a Pull Request](https://github.com/localstack-dotnet/localstack-dotnet-client/compare) ## đŸ€ Code of Conduct -This project follows the [.NET Foundation Code of Conduct](.github/CODE_OF_CONDUCT.md). By participating, you're expected to uphold this code. Please report unacceptable behavior to [localstack.dotnet@gmail.com](mailto:localstack.dotnet@gmail.com). +This project follows the [.NET Foundation Code of Conduct](CODE_OF_CONDUCT.md). By participating, you're expected to uphold this code. Please report unacceptable behavior to [localstack.dotnet@gmail.com](mailto:localstack.dotnet@gmail.com). ## 📝 Contributor License Agreement (CLA) @@ -25,15 +25,15 @@ This project follows the [.NET Foundation Code of Conduct](.github/CODE_OF_CONDU We maintain a **dual-track versioning strategy**: - **v2.x (AWS SDK v4)** - Active development on [`master`](https://github.com/localstack-dotnet/localstack-dotnet-client/tree/master) branch -- **v1.x (AWS SDK v3)** - Long-term support on [`sdkv3-lts`](https://github.com/localstack-dotnet/localstack-dotnet-client/tree/sdkv3-lts) branch (maintained until July 2026) +- **v1.x (AWS SDK v3)** - The [`sdkv3-lts`](https://github.com/localstack-dotnet/localstack-dotnet-client/tree/sdkv3-lts) branch preserves published releases but is no longer supported; its maintenance window ended in July 2026. See the [security policy](SECURITY.md). -When contributing, please specify which version track your contribution targets. +New changes target v2.x on `master`. The v1.x branch is not accepting maintenance fixes. ## 🚀 Getting Started ### Prerequisites -- [.NET SDK 8.0+](https://dotnet.microsoft.com/download) (for development) +- A [.NET SDK](https://dotnet.microsoft.com/download) compatible with the repository's [`global.json`](../global.json) (for development) - [Docker](https://docs.docker.com/get-docker/) (for LocalStack testing) - [Git](https://git-scm.com/downloads) - IDE: [Visual Studio](https://visualstudio.microsoft.com/), [Rider](https://www.jetbrains.com/rider/), or [VS Code](https://code.visualstudio.com/) @@ -61,16 +61,17 @@ When contributing, please specify which version track your contribution targets. ./build.sh ``` + On Unix, the Cake initialization task changes your global Git `core.autocrlf` setting. Read the [quality gates](../docs/engineering/quality-gates.md) before using the script on a shared development machine. + 3. **Run Tests** ```bash - # All tests (requires Docker for functional tests) + # Default unit and client-construction tests (functional tests are skipped) .\build.ps1 --target tests - - # Unit/Integration tests only - .\build.ps1 --target tests --skipFunctionalTest true ``` + Functional tests require LocalStack containers. The Cake opt-in task attempts to remove **every** Docker container returned by `docker ps --all`, not only this project's containers. Use an isolated Docker daemon before opting in; see [quality gates](../docs/engineering/quality-gates.md). + ## 🐛 Reporting Issues ### Before Creating an Issue @@ -124,7 +125,7 @@ We love new ideas! Here's how to suggest features: 3. **Test thoroughly** ```bash - # Run all tests + # Run the default suite (functional tests skipped) ./build.sh --target tests # Test specific scenarios with LocalStack @@ -143,7 +144,7 @@ We love new ideas! Here's how to suggest features: - Use our [PR Template](https://github.com/localstack-dotnet/localstack-dotnet-client/compare) - Provide clear description of changes - Link related issues - - Specify target version track (v1.x or v2.x) + - Target the supported v2.x line ### Code Quality Standards @@ -201,6 +202,6 @@ Contributors are recognized in: --- -**By contributing to this project, you agree to abide by our [Code of Conduct](.github/CODE_OF_CONDUCT.md) and understand that your contributions will be licensed under the MIT License.** +**By contributing to this project, you agree to abide by our [Code of Conduct](CODE_OF_CONDUCT.md) and understand that your contributions will be licensed under the MIT License.** Thank you for making LocalStack .NET Client better! 🚀 diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index b1d4ca7..1e38ed9 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -32,10 +32,12 @@ A clear and concise description of what you expected to happen. **LocalStack.Client Version:** -- [ ] v1.x (AWS SDK v3) - LTS Branch +- [ ] v1.x (AWS SDK v3) - Unsupported historical release - [ ] v2.x (AWS SDK v4) - Current Branch - Version: +The v1.x maintenance window ended in July 2026; new fixes target v2.x. See the [security policy](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/.github/SECURITY.md). + **LocalStack Information:** - LocalStack Version: diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 000290f..8e9bf6e 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -26,9 +26,9 @@ Provide a clear and concise description of the changes. ## 🎯 Target Version Track -- [ ] v1.x (AWS SDK v3) - LTS Branch (`sdkv3-lts`) -- [ ] v2.x (AWS SDK v4) - Current Branch (`master`) -- [ ] Both versions (requires separate PRs) +- [ ] v2.x (AWS SDK v4) - Supported branch (`master`) + +The v1.x / AWS SDK v3 line is no longer supported; do not target new fixes to `sdkv3-lts`. See the [security policy](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/.github/SECURITY.md). ## đŸ§Ș Testing @@ -98,6 +98,6 @@ If applicable, add screenshots or code examples showing the changes in action. By submitting this pull request, I confirm that: -- [ ] I have read and agree to the project's [Code of Conduct](.github/CODE_OF_CONDUCT.md) -- [ ] I understand that this contribution may be subject to the [.NET Foundation CLA](.github/CONTRIBUTING.md) +- [ ] I have read and agree to the project's [Code of Conduct](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/.github/CODE_OF_CONDUCT.md) +- [ ] I understand that this contribution may be subject to the [.NET Foundation CLA](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/.github/CONTRIBUTING.md) - [ ] My contribution is licensed under the same terms as the project (MIT License) diff --git a/.github/SECURITY.md b/.github/SECURITY.md index 75221be..b86889e 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -2,20 +2,20 @@ ## Supported Versions -We maintain a dual-track versioning strategy with different support levels for each track. Security patches are released based on the CVSS v3.0 Rating and version track: +Security patches are released for the supported v2.x line according to the CVSS v3.0 rating below. Previously published v1.x packages remain available, but availability does not mean the line is still maintained. ### Version Tracks - **v2.x (AWS SDK v4)**: Active development on [master branch](https://github.com/localstack-dotnet/localstack-dotnet-client/tree/master) -- **v1.x (AWS SDK v3)**: Long-term support (LTS) on [sdkv3-lts branch](https://github.com/localstack-dotnet/localstack-dotnet-client/tree/sdkv3-lts), maintained until **July 2026** +- **v1.x (AWS SDK v3)**: The [sdkv3-lts branch](https://github.com/localstack-dotnet/localstack-dotnet-client/tree/sdkv3-lts) is no longer supported. Its announced maintenance window ended in **July 2026**. We do not plan further v1.x bug fixes, security patches, or service updates; migrate to v2.x. The upstream [AWS SDK for .NET v3 reached end-of-support on June 1, 2026](https://aws.amazon.com/blogs/devops/announcing-the-end-of-support-for-the-aws-sdk-for-net-v3/). ### Security Patch Policy -| CVSS v3.0 | v2.x (Current) | v1.x (LTS) | -| --------- | -------------- | ---------- | -| 9.0-10.0 | ✅ All releases within previous 3 months | ✅ Latest LTS release | -| 4.0-8.9 | ✅ Most recent release | ✅ Latest LTS release | -| < 4.0 | ⚠ Best effort | ❌ No patches (upgrade recommended) | +| CVSS v3.0 | v2.x (Current) | +| --------- | -------------- | +| 9.0-10.0 | ✅ All releases within previous 3 months | +| 4.0-8.9 | ✅ Most recent release | +| < 4.0 | ⚠ Best effort | ## Reporting a Vulnerability @@ -59,4 +59,4 @@ Security updates will be released as soon as possible after a vulnerability is c ## Comments on this Policy -If you have suggestions on how this process could be improved, please submit a pull request or open an issue to discuss. \ No newline at end of file +If you have suggestions on how this process could be improved, please submit a pull request or open an issue to discuss. diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md deleted file mode 100644 index 9cf7ea2..0000000 --- a/.github/copilot-instructions.md +++ /dev/null @@ -1,214 +0,0 @@ -# LocalStack .NET Client - AI Agent Instructions - -Hey Copilot, welcome to the team! Before we start writing some brilliant code, let's get aligned on how we'll work together. Think of this as our "prime directive." - -## **1. Our Partnership Philosophy** - -* **Be my brainstorming partner:** Be talkative, conversational, and don't be afraid to use some quick and clever humor. We're in this together, so let's make it fun. -* **Innovate, but be practical:** I love creative, outside-the-box thinking. But at the end of the day, our code needs to be robust, maintainable, and solve the problem at hand. Practicality is king. -* **Challenge me:** I'm not looking for a yes-person. If you see a flaw in my logic, a potential edge case I've missed, or a more elegant solution, please speak up! I expect you to provide constructive criticism and explain the "why" behind your suggestions. A healthy debate leads to better code. - -## **2. The "Plan-Then-Execute" Rule** - -This is the most important rule: **Do not write a full implementation without my approval.** - -* **Step 1: Propose a plan.** Before generating any significant block of code, first outline your approach. This could be pseudo-code, a list of steps, or a high-level description of the classes and methods you'll create. -* **Step 2: Wait for the green light.** I will review your plan and give you the go-ahead. This ensures we're on the same page before you invest time generating the full implementation. - -## **3. Technical Ground Rules** - -* **Centralized NuGet Management:** This solution uses centralized package management. When a new package is needed, you should: - 1. Add a PackageReference to the Directory.Packages.props file, specifying both the Include and Version attributes. - 2. Add a corresponding PackageReference with only the Include attribute to the relevant .csproj file. -* **Testing Our Code:** Our testing stack is **xUnit**, **Moq**, and **Testcontainers**. Please generate tests following the patterns and best practices for these frameworks. Use Fact and Theory attributes from xUnit, set up fakes with Mock, and help configure services for integration tests using Testcontainers. -* **Roslyn Analyzers Are King (Usually):** We adhere to our configured analyzer rules. However, if we're quickly testing an idea or prototyping, you can safely use #pragma warning disable to ignore a specific rule. Just be sure to add a comment like // TODO: Re-address this analyzer warning so we can clean it up later. -* **Modern C#:** Let's default to modern C# conventions: file-scoped namespaces, record types for DTOs, top-level statements, expression-bodied members, and async/await best practices. - -## Project Overview - -**LocalStack .NET Client** is a sophisticated .NET library that wraps the AWS SDK to work seamlessly with LocalStack (local AWS emulation). The project is undergoing a major architectural evolution with **Native AOT support** via source generators and **AWS SDK v4 migration**. - -> 📖 **Deep Dive**: For comprehensive project details, see [`artifacts/Project_Onboarding.md`](../artifacts/Project_Onboarding.md) - a detailed guide covering architecture, testing strategy, CI/CD pipeline, and contribution guidelines. - -### What I Learned from the Onboarding Document - -**Key Insights for AI Agents:** - -1. **Testing is Sophisticated**: The project uses a 4-tier testing pyramid (Unit → Integration → Functional → Sandbox). Functional tests use **TestContainers** with dynamic port mapping across multiple LocalStack versions (v3.7.1, v4.3.0). - -2. **Version-Aware Development**: The project carefully manages AWS SDK compatibility. Currently migrated to **AWS SDK v4** with specific considerations: - - .NET Framework requirement bumped from 4.6.2 → 4.7.2 - - Extensions package uses new `ClientFactory` pattern vs old non-generic `ClientFactory` - - Some functional tests may fail due to behavioral changes in SNS/DynamoDB operations - -3. **Enterprise Build System**: Uses **Cake Frosting** (not traditional Cake scripts) with cross-platform CI/CD across Ubuntu/Windows/macOS. The build system handles complex scenarios like .NET Framework testing on Mono. - -4. **Service Coverage**: Supports **50+ AWS services** through intelligent endpoint resolution. Services are mapped through `AwsServiceEndpointMetadata.All` with both legacy per-service ports and modern unified edge port (4566). - -5. **Reflection Strategy**: The codebase heavily uses reflection to access AWS SDK internals (private `serviceMetadata` fields, dynamic `ClientConfig` creation). This is being modernized with UnsafeAccessor for AOT. - -### Core Architecture - -The library follows a **Session-based architecture** with three main components: - -1. **Session (`ISession`)**: Core client factory that configures AWS clients for LocalStack endpoints -2. **Config (`IConfig`)**: Service endpoint resolution and LocalStack connection management -3. **SessionReflection (`ISessionReflection`)**: Abstraction layer for AWS SDK private member access - -### Key Innovation: Dual Reflection Strategy - -The project uses a sophisticated **conditional compilation pattern** for .NET compatibility: - -- **.NET 8+**: Uses **UnsafeAccessor** pattern via Roslyn source generators (`LocalStack.Client.Generators`) for Native AOT -- **Legacy (.NET Standard 2.0, .NET Framework)**: Falls back to traditional reflection APIs - -## Development Workflows - -### Build System -- **Build Scripts**: Use `build.ps1` (Windows) or `build.sh` (Linux) - these delegate to Cake build tasks -- **Build Framework**: Uses **Cake Frosting** in `build/LocalStack.Build/` - examine `CakeTasks/` folder for available targets -- **Common Commands**: - - `build.ps1` - Full build and test - - `build.ps1 --target=tests` - Run tests only - -### Project Structure - -``` -src/ -├── LocalStack.Client/ # Core library (multi-target: netstandard2.0, net472, net8.0, net9.0) -├── LocalStack.Client.Extensions/ # DI integration (AddLocalStack() extension) -└── LocalStack.Client.Generators/ # Source generator for AOT (netstandard2.0, Roslyn) - -tests/ -├── LocalStack.Client.Tests/ # Unit tests (mocked) -├── LocalStack.Client.Integration.Tests/ # Real LocalStack integration -├── LocalStack.Client.AotCompatibility.Tests/ # Native AOT testing -└── sandboxes/ # Example console apps -``` - -## Critical Patterns & Conventions - -### 1. Multi-Framework Configuration Pattern - -For .NET 8+ conditional features, use this pattern consistently: - -```csharp -#if NET8_0_OR_GREATER - // Modern implementation (UnsafeAccessor) - var accessor = AwsAccessorRegistry.GetByInterface(); - return accessor.CreateClient(credentials, clientConfig); -#else - // Legacy implementation (reflection) - return CreateClientByInterface(typeof(TClient), useServiceUrl); -#endif -``` - -### 2. Session Client Creation Pattern - -The Session class provides multiple client creation methods - understand the distinction: - -- `CreateClientByInterface()` - Interface-based (preferred) -- `CreateClientByImplementation()` - Concrete type -- `useServiceUrl` parameter controls endpoint vs region configuration - -### 3. Source Generator Integration - -When working on AOT features: -- Generator runs only for .NET 8+ projects (`Net8OrAbove` condition) -- Discovers AWS clients from referenced assemblies at compile-time -- Generates `IAwsAccessor` implementations in `LocalStack.Client.Generated` namespace -- Auto-registers via `ModuleInitializer` in `AwsAccessorRegistry` - -### 4. Configuration Hierarchy - -LocalStack configuration follows this pattern: -```json -{ - "LocalStack": { - "UseLocalStack": true, - "Session": { - "RegionName": "eu-central-1", - "AwsAccessKeyId": "accessKey", - "AwsAccessKey": "secretKey" - }, - "Config": { - "LocalStackHost": "localhost.localstack.cloud", - "EdgePort": 4566, - "UseSsl": false - } - } -} -``` - -## Testing Patterns - -### Multi-Layered Testing Strategy -Based on the comprehensive testing guide in the onboarding document: - -- **Unit Tests**: `MockSession.Create()` → Setup mocks → Verify calls pattern -- **Integration Tests**: Client creation across **50+ AWS services** without external dependencies -- **Functional Tests**: **TestContainers** with multiple LocalStack versions (v3.7.1, v4.3.0) -- **Sandbox Apps**: Real-world examples in `tests/sandboxes/` demonstrating usage patterns - -### TestContainers Pattern -```csharp -// Dynamic port mapping prevents conflicts -ushort mappedPublicPort = localStackFixture.LocalStackContainer.GetMappedPublicPort(4566); -``` - -### Known Testing Challenges -- **SNS Issues**: LocalStack v3.7.2/v3.8.0 have known SNS bugs (use v3.7.1 or v3.9.0+) -- **SQS Compatibility**: AWSSDK.SQS 3.7.300+ has issues with LocalStack v1/v2 -- **AWS SDK v4 Migration**: Some functional tests may fail due to behavioral changes - -## Package Management - -**Centralized Package Management** - Always follow this two-step process: - -1. Add to `Directory.Packages.props`: -```xml - -``` - -2. Reference in project: -```xml - -``` - -### Code Quality Standards -The onboarding document emphasizes **enterprise-level quality**: -- **10+ Analyzers Active**: Roslynator, SonarAnalyzer, Meziantou.Analyzer, SecurityCodeScan -- **Warnings as Errors**: `TreatWarningsAsErrors=true` across solution -- **Nullable Reference Types**: Enabled solution-wide for safety -- **Modern C# 13**: Latest language features with strict mode enabled - -## Working with AWS SDK Integration - -### Service Discovery Pattern -The library auto-discovers AWS services using naming conventions: -- `IAmazonS3` → `AmazonS3Client` → `AmazonS3Config` -- Service metadata extracted from private static `serviceMetadata` fields -- Endpoint mapping in `AwsServiceEndpointMetadata.All` - -### Reflection Abstraction -When adding AWS SDK integration features: -- Always implement in both `SessionReflectionLegacy` and `SessionReflectionModern` -- Modern version uses generated `IAwsAccessor` implementations -- Legacy version uses traditional reflection with error handling - -## Key Files to Understand - -- `src/LocalStack.Client/Session.cs` - Core client factory logic -- `src/LocalStack.Client/Utils/SessionReflection.cs` - Facade that chooses implementation -- `src/LocalStack.Client.Generators/AwsAccessorGenerator.cs` - Source generator main logic -- `tests/sandboxes/` - Working examples of all usage patterns -- `Directory.Build.props` - Shared MSBuild configuration with analyzer rules - -## Plan-Then-Execute Workflow - -1. **Propose architectural approach** - especially for cross-framework features -2. **Consider AOT implications** - will this work with UnsafeAccessor pattern? -3. **Plan test strategy** - unit, integration, and AOT compatibility -4. **Wait for approval** before implementing significant changes - -The codebase prioritizes **backwards compatibility** and **AOT-first design** - keep these principles central to any contributions. \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..6300c3f --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,28 @@ +# LocalStack .NET Client — agent guide + +This public repository owns its current behavior, terminology, and accepted decisions. Read the document for the task; avoid loading historical plans or a full tool inventory for every change. + +## Always + +- Check Git status before editing. Preserve changes and deletions you did not make. +- Use the checked-in source, projects, workflows, and their pinned versions for implementation facts. Treat locally ignored `artifacts/` files and unmerged branches as dated leads, not current policy. +- Keep the [root README](README.md) and the two tracked package README copies consistent; both packages include that text. Check the actual package feed before claiming a declared version is published. +- Before using Cake functional tests, read [quality gates](docs/engineering/quality-gates.md): their cleanup is not limited to this project's Docker containers. Cake builds on Unix and Extensions package preparation also change state outside the expected test outputs. +- If sources conflict or a public support claim lacks evidence, follow the [deviation protocol](docs/engineering/deviation-protocol.md). Preserve the uncertainty rather than selecting a convenient answer. + +## Task routing + +| Task | Read first | +| --- | --- | +| Core session, AWS client creation, endpoint catalog, or service-support wording | [Client runtime](docs/architecture/client-runtime.md) and [glossary](GLOSSARY.md) | +| `AddLocalStack`, DI, AWS-mode factory, or Extensions | [Extensions and composition](docs/architecture/extensions-and-composition.md) | +| Target frameworks, package versions, packaging, or Native AOT claims | [Platform and packaging](docs/architecture/platform-and-packaging.md); verify values in the linked project/configuration files | +| Tests, build scripts, Docker, CI, or release-task safety | [Quality gates](docs/engineering/quality-gates.md) and the relevant task/workflow source | +| Document placement, dates, relays, or historical evidence | [Documentation ownership](docs/engineering/documentation.md) | +| An accepted, hard-to-reverse design choice | [ADR eligibility and records](docs/adr/README.md) | +| Consumer setup and package installation | [README](README.md) | +| Contributions and PRs | [Contribution guide](.github/CONTRIBUTING.md) | +| Release changes | [Changelog](CHANGELOG.md) | +| Security disclosure or support window | [Security policy](.github/SECURITY.md) | + +Current architecture documents describe `master`; a draft source-generator branch does not establish Native AOT support here. The private research archive, if created, cannot be required to understand this public canon. diff --git a/GLOSSARY.md b/GLOSSARY.md new file mode 100644 index 0000000..a71a28e --- /dev/null +++ b/GLOSSARY.md @@ -0,0 +1,29 @@ +# LocalStack .NET Client + +This glossary distinguishes the library's concepts from the LocalStack emulator and the AWS SDK. It describes language, not package configuration or a service-compatibility matrix. + +## Language + +**Cataloged AWS service**: +An AWS service with a LocalStack endpoint mapping in this library. Its presence in the catalog does not assert that the emulator implements every operation. +_Avoid_: Supported service, when only catalog membership is known. + +**LocalStack-configured AWS service client**: +An AWS SDK service client created through this library's LocalStack session. It is not the emulator service or a guarantee that every later request reaches a particular destination. +_Avoid_: LocalStack service, when referring to the client object. + +**AWS service ID**: +The AWS SDK service identifier used to match a service to this library's endpoint catalog. It is distinct from the service's CLI name and the `AwsService` catalog key. +_Avoid_: CLI name, enum name, or an unqualified service name for this identifier. + +**Configured LocalStack endpoint**: +The host, scheme, and port this library associates with a cataloged AWS service. Several services can share a port, and the configured endpoint alone does not establish which operations the emulator supports. +_Avoid_: AWS region or service ID as synonyms for an endpoint. + +**LocalStack mode / AWS mode**: +The application-level choice between creating an AWS service client through this library's LocalStack session and creating it through the ordinary AWS SDK factory. This choice describes client creation, not an unconditional promise about subsequent network requests. +_Avoid_: LocalStack mode for the separate choice between an explicit service URL and a region-based client configuration. + +**LocalStack.NET version line**: +A major-version family of this library's packages: v1.x targets AWS SDK v3, and v2.x targets AWS SDK v4. It is separate from the LocalStack emulator image version and the version of an individual AWS SDK package. +_Avoid_: An unqualified “LocalStack version” when referring to the library. diff --git a/README.md b/README.md index c4fa022..d1986b8 100644 --- a/README.md +++ b/README.md @@ -2,27 +2,25 @@ [![Nuget](https://img.shields.io/nuget/dt/LocalStack.Client)](https://www.nuget.org/packages/LocalStack.Client/) [![NuGet v2.x](https://img.shields.io/endpoint?url=https%3A%2F%2Fyvfdbfas85.execute-api.eu-central-1.amazonaws.com%2Flive%2F%3Fpackage%3Dlocalstack.client%26source%3Dnuget%26track%3D2%26includeprerelease%3Dtrue%26label%3Dnuget)](https://www.nuget.org/packages/LocalStack.Client/) [![NuGet v1.x](https://img.shields.io/endpoint?url=https%3A%2F%2Fyvfdbfas85.execute-api.eu-central-1.amazonaws.com%2Flive%2F%3Fpackage%3Dlocalstack.client%26source%3Dnuget%26track%3D1%26includeprerelease%3Dtrue%26label%3Dnuget)](https://www.nuget.org/packages/LocalStack.Client/) [![CI/CD Pipeline](https://github.com/localstack-dotnet/localstack-dotnet-client/actions/workflows/ci-cd.yml/badge.svg)](https://github.com/localstack-dotnet/localstack-dotnet-client/actions/workflows/ci-cd.yml) [![Security](https://github.com/localstack-dotnet/localstack-dotnet-client/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/localstack-dotnet/localstack-dotnet-client/actions/workflows/github-code-scanning/codeql) [![Linux Tests](https://img.shields.io/endpoint?url=https://yvfdbfas85.execute-api.eu-central-1.amazonaws.com/live/badge/tests/linux?label=Tests)](https://yvfdbfas85.execute-api.eu-central-1.amazonaws.com/live/redirect/test-results/linux) -> **🚀 Quick Start**: `dotnet add package LocalStack.Client --version 2.0.0` (AWS SDK v4) | [Installation Guide](#-installation) | [GA Timeline](https://github.com/localstack-dotnet/localstack-dotnet-client/discussions/45) +> **🚀 Quick Start**: `dotnet add package LocalStack.Client --version 2.0.0` (AWS SDK v4) | [Package installation](#-package-installation) | [Migration context](https://github.com/orgs/localstack-dotnet/discussions/45) --- ## 🎉 What's New: AWS SDK v4 Support Available -**v2.0.0** is live with complete AWS SDK v4 support - easier migration than expected! +**v2.0.0** introduced AWS SDK for .NET v4 compatibility. Service reachability depends on this library's catalog mapping and the capabilities of the LocalStack release and edition you use. -- ✅ **1,168 tests passing** across all frameworks -- ✅ **Minimal breaking changes** (just .NET Framework 4.6.2 → 4.7.2 and AWS SDK v3 → v4) -- ✅ **Public APIs unchanged** - your code should work as-is! -- 📖 **[Read Full Roadmap](https://github.com/localstack-dotnet/localstack-dotnet-client/discussions/45)** +- đŸ§Ș Unit tests, AWS client-construction tests, and container-backed functional tests cover different parts of the library. See the [test and CI boundaries](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/docs/engineering/quality-gates.md) rather than relying on a fixed pass count. +- ⚠ **Migration changes** include .NET Framework 4.6.2 → 4.7.2 and AWS SDK v3 → v4; see the [changelog](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/CHANGELOG.md) before upgrading. **Version Strategy**: - v2.x (AWS SDK v4) active development on [master branch](https://github.com/localstack-dotnet/localstack-dotnet-client/tree/master) -- v1.x (AWS SDK v3) Available on [sdkv3-lts branch](https://github.com/localstack-dotnet/localstack-dotnet-client/tree/sdkv3-lts), maintenance until July 2026 +- v1.x (AWS SDK v3) remains available on the [sdkv3-lts branch](https://github.com/localstack-dotnet/localstack-dotnet-client/tree/sdkv3-lts), but support ended in July 2026. Use v2.x for maintained releases; see the [security policy](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/.github/SECURITY.md). ![LocalStack](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/assets/localstack-dotnet.png?raw=true) -Localstack.NET is an easy-to-use .NET client for [LocalStack](https://github.com/localstack/localstack), a fully functional local AWS cloud stack. The client library provides a thin wrapper around [aws-sdk-net](https://github.com/aws/aws-sdk-net) which automatically configures the target endpoints to use LocalStack for your local cloud application development. +LocalStack.NET is a .NET client library for [LocalStack](https://github.com/localstack/localstack), a local AWS cloud emulator. It configures AWS SDK clients for LocalStack when LocalStack mode is enabled; the same application registration can instead create ordinary AWS clients. ## 🚀 Platform Compatibility & Quality Status @@ -36,53 +34,8 @@ Localstack.NET is an easy-to-use .NET client for [LocalStack](https://github.com > **Heads‑up for `dotnet publish -p:PublishAot=true` / `PublishTrimmed=true` users** -- **v2.0.0 GA ships without Native AOT support.** - The current build still relies on reflection for some AWS SDK internals. - - Public entry points that touch reflection are tagged with - `[RequiresDynamicCode]` / `[RequiresUnreferencedCode]`. - - You’ll see IL3050 / IL2026 warnings at compile time (promoted to errors in a strict AOT publish). -- We already ship a linker descriptor with **`LocalStack.Client.Extensions`** - to keep the private `ClientFactory` machinery alive. **Nothing to configure for that part.** -- Until the reflection‑free, source‑generated path lands (work in progress in - [draft PR #49](https://github.com/localstack-dotnet/localstack-dotnet-client/pull/49) and tracked on - [roadmap #48](https://github.com/localstack-dotnet/localstack-dotnet-client/discussions/48)): - - 1. **Suppress** the warnings in your app *or* call only the APIs that don’t rely on reflection. - 2. Add a tiny **service‑specific** linker descriptor for every `AWSSDK.*` package you reference - (S3, DynamoDB, etc.). For example, for S3: - - ```xml - - - - - - - - - - - - - - - - ``` - - 3. Wire it into your project once: - - ```xml - - - - ``` - - 4. If you hit a runtime “missing member” error, ensure you’re on AWS SDK v4 **≄ 4.1.\*** and that - the concrete `AWSSDK.*` package you’re using is included in the descriptor above. - -> **Planned** – v2.1 will introduce an AOT‑friendly factory that avoids reflection entirely; once you -> migrate to that API these warnings and extra XML files go away. +- **The current v2 packages do not support Native AOT.** Both client-creation paths still use reflection over AWS SDK internals. Entry points carry `[RequiresDynamicCode]` and `[RequiresUnreferencedCode]` annotations where available, and Extensions embeds a linker descriptor for its internal AWS factory; neither guarantees that an application will trim or publish successfully with Native AOT. +- The reflection-free source-generator work is in [draft PR #49](https://github.com/localstack-dotnet/localstack-dotnet-client/pull/49), not in `master`. Do not suppress trimming/AOT warnings or adopt an unverified service descriptor on the assumption that this draft has shipped. See the [platform boundary](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/docs/architecture/platform-and-packaging.md). ### Build & Test Matrix @@ -96,7 +49,7 @@ Localstack.NET is an easy-to-use .NET client for [LocalStack](https://github.com ## Package Status -| Package | NuGet.org | GitHub Packages (Nightly) | +| Package | NuGet.org | GitHub Packages (development builds) | |---------|-----------|---------------------------| | **LocalStack.Client v1.x** | [![NuGet v1.x](https://img.shields.io/endpoint?url=https%3A%2F%2Fyvfdbfas85.execute-api.eu-central-1.amazonaws.com%2Flive%2Fbadge%2Fpackages%2Flocalstack.client%3Fsource%3Dnuget%26track%3D1%26label%3Dnuget)](https://www.nuget.org/packages/LocalStack.Client/) | [![Github v1.x](https://img.shields.io/endpoint?url=https%3A%2F%2Fyvfdbfas85.execute-api.eu-central-1.amazonaws.com%2Flive%2Fbadge%2Fpackages%2Flocalstack.client%3Fsource%3Dgithub%26track%3D1%26includeprerelease%3Dtrue%26label%3Dgithub)](https://github.com/localstack-dotnet/localstack-dotnet-client/pkgs/nuget/LocalStack.Client) | | **LocalStack.Client v2.x** | [![NuGet v2.x](https://img.shields.io/endpoint?url=https%3A%2F%2Fyvfdbfas85.execute-api.eu-central-1.amazonaws.com%2Flive%2Fbadge%2Fpackages%2Flocalstack.client%3Fsource%3Dnuget%26track%3D2%26includeprerelease%3Dtrue%26label%3Dnuget)](https://www.nuget.org/packages/LocalStack.Client/) | [![Github v2.x](https://img.shields.io/endpoint?url=https%3A%2F%2Fyvfdbfas85.execute-api.eu-central-1.amazonaws.com%2Flive%2Fbadge%2Fpackages%2Flocalstack.client%3Fsource%3Dgithub%26track%3D2%26includeprerelease%3Dtrue%26label%3Dgithub)](https://github.com/localstack-dotnet/localstack-dotnet-client/pkgs/nuget/LocalStack.Client) | @@ -125,7 +78,7 @@ Localstack.NET is an easy-to-use .NET client for [LocalStack](https://github.com - **Adaptable Environment Transition:** Easily switch between LocalStack and actual AWS services with minimal configuration changes. -- **Versatile .NET Compatibility:** Supports a broad spectrum of .NET versions, from .NET 9.0 and .NET Standard 2.0 to .NET Framework 4.6.2 and above. +- **Versatile .NET Compatibility:** Both packages target .NET 8, .NET 9, and .NET Standard 2.0; Core also has an explicit .NET Framework 4.7.2 target. See [platform and packaging](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/docs/architecture/platform-and-packaging.md) for the exact project targets. - **Reduced Learning Curve:** Offers a familiar interface tailored for LocalStack, ideal for developers acquainted with the AWS SDK for .NET. @@ -146,9 +99,9 @@ LocalStack.NET is available through multiple package sources to support differen To install the latest version of LocalStack.NET with AWS SDK v4 support, use the following command: ```bash -# Install v2.0.0 with AWS SDK v4 support +# Install the published v2 releases with AWS SDK v4 support dotnet add package LocalStack.Client --version 2.0.0 -dotnet add package LocalStack.Client.Extensions --version 2.0.0 +dotnet add package LocalStack.Client.Extensions --version 2.0.1 ``` #### Development Builds (GitHub Packages) @@ -183,14 +136,14 @@ public void ConfigureServices(IServiceCollection services) // Add framework services. services.AddMvc(); - services.AddLocalStack(Configuration) + services.AddLocalStack(Configuration); services.AddDefaultAWSOptions(Configuration.GetAWSOptions()); services.AddAwsService(); services.AddAwsService(); } ``` -The `AddLocalStack` method integrates LocalStack.NET into your application, and the `AddAwsService` method allows you to specify which AWS services you want to use with LocalStack. +`AddLocalStack` binds configuration and registers the library's services. `AddAwsService` registers the AWS service interface; `LocalStack:UseLocalStack` selects whether that interface is created through the LocalStack session or the ordinary AWS SDK factory. The default is `false`. See [client runtime and service support](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/docs/architecture/client-runtime.md) for what the endpoint catalog does—and does not—promise. (Alternatively, `AddAWSServiceLocalStack` method can be used to prevent mix-up with `AddAWSService`.) @@ -243,11 +196,7 @@ The `RegionName` is important as LocalStack creates resources based on the speci - **LocalStack Versions v2.0.1 - v2.2:** In versions v2.0.1 through v2.2 of LocalStack, the URL routing logic was changed, causing issues with SQS and S3 operations. Two issues were opened in LocalStack regarding this: [issue #8928](https://github.com/localstack/localstack/issues/8928) and [issue #8924](https://github.com/localstack/localstack/issues/8924). LocalStack addressed this problem with [PR #8962](https://github.com/localstack/localstack/pull/8962). Therefore, when using LocalStack.NET, either use version v2.0 of LocalStack (there are no issues with the v1 series as well) or the upcoming v2.3 version, or use the latest v3 series container from Docker Hub. -- **AWS_SERVICE_URL Environment Variable:** Unexpected behaviors might occur in LocalStack.NET when the `AWS_SERVICE_URL` environment variable is set. This environment variable is typically set by LocalStack in the container when using AWS Lambda, and AWS also uses this environment variable in the live environment. Soon, just like in LocalStack's official Python library, this environment variable will be prioritized by LocalStack.NET when configuring the LocalStack host, and there will be a general simplification in the configuration. You can follow this in the issues [issue #27](https://github.com/localstack-dotnet/localstack-dotnet-client/issues/27) and [issue #32](https://github.com/localstack-dotnet/localstack-dotnet-client/issues/32). You set the `AWS_SERVICE_URL` to empty string until this issue is resolved. - -```csharp -Environment.SetEnvironmentVariable("AWS_SERVICE_URL", string.Empty); -``` +- **Endpoint environment variables:** [Issue #27](https://github.com/localstack-dotnet/localstack-dotnet-client/issues/27#issuecomment-4937111791) records a 2026-07-10 SQS observation against Extensions 2.0.0. With `UseLocalStack=true`, a LocalStack proxy aimed at A and `AWS_ENDPOINT_URL` aimed at B sent traffic to A. With `UseLocalStack=false`, the proxy was unset and traffic followed B. This is a dated report, not a re-run against every SDK or service; the issue remains open and no general precedence fix is merged. `AWS_SERVICE_URL` can also appear in Lambda environments, but this library does not define a general override rule for it. Diagnose the actual SDK configuration before adopting an environment-variable workaround. - **IAmazonLambda Operations:** There's a general issue with `IAmazonLambda` operations. This matter is currently under investigation. @@ -273,6 +222,8 @@ Linux ./build.sh ``` +On Unix, this Cake script runs an initialization task that changes your global Git `core.autocrlf` setting. Read the [quality gates](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/docs/engineering/quality-gates.md) before running it on a shared machine. + ### Sandbox Applications The LocalStack .NET repository includes several sandbox console applications located in [tests/sandboxes](https://github.com/localstack-dotnet/localstack-dotnet-client/tree/master/tests/sandboxes). These applications serve both as testing tools and as examples. Refer to [the documentation](https://github.com/localstack-dotnet/localstack-dotnet-client/wiki/Developing#sandbox-applications) for more information @@ -301,8 +252,8 @@ Got questions or wild feature ideas? ## Changelog -Please refer to [`CHANGELOG.md`](CHANGELOG.md) to see the complete list of changes for each release. +Please refer to [`CHANGELOG.md`](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/CHANGELOG.md) to see the complete list of changes for each release. ## License -Licensed under MIT, see [LICENSE](LICENSE) for the full text. +Licensed under MIT, see [LICENSE](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/LICENSE) for the full text. diff --git a/docs/adr/0001-aws-sdk-v4-and-v1-maintenance.md b/docs/adr/0001-aws-sdk-v4-and-v1-maintenance.md new file mode 100644 index 0000000..9177236 --- /dev/null +++ b/docs/adr/0001-aws-sdk-v4-and-v1-maintenance.md @@ -0,0 +1,9 @@ +# Migrate to AWS SDK v4 on the v2 line while retaining a v1 line + +Date: 2025-07-16 + +AWS SDK v4 changed more of the SDK integration surface than the first `ClientFactory` failure exposed. Rather than patch v1 for that one symptom, the project moved the existing `LocalStack.Client` and `LocalStack.Client.Extensions` package identities to a v2 line using AWS SDK v4 on `master`, while retaining AWS SDK v3 on `sdkv3-lts` to give existing users migration time. This changes SDK compatibility and the explicit .NET Framework target from 4.6.2 to 4.7.2. + +**Consequences:** Maintaining two lines costs backports. The security policy says v1 was maintained “until July 2026”; the subsequently edited [announcement](https://github.com/orgs/localstack-dotnet/discussions/45) specifies July 31, 2026. This historical record does not establish support after that window or turn the announcement's exact day into the policy file's wording. The first-party record explains the rejected temporary v1 patch, but not why the existing package names were preferred over separate v4-suffixed names. + +**Evidence:** [Maintainer announcement (subsequently edited)](https://github.com/orgs/localstack-dotnet/discussions/45), [AWS SDK v4 merge PR #46](https://github.com/localstack-dotnet/localstack-dotnet-client/pull/46), and the [v2 migration changelog](../../CHANGELOG.md). The merge date identifies acceptance of the v2 code; it is not the later GA publication date. diff --git a/docs/adr/0002-aws-setup-constructor-compatibility.md b/docs/adr/0002-aws-setup-constructor-compatibility.md new file mode 100644 index 0000000..a99ef8a --- /dev/null +++ b/docs/adr/0002-aws-setup-constructor-compatibility.md @@ -0,0 +1,9 @@ +# Keep the AWS client factory compatible with changed SDK internals + +Date: 2026-07-29 + +`AWSSDK.Extensions.NETCore.Setup` 4.0.4 added an optional parameter to the internal `ClientFactory` constructor, breaking this library's exact-signature reflection lookup when `UseLocalStack` was false. The #52 fix selects a non-public constructor with `AWSOptions` first and prefers the fewest parameters, supplies trailing defaults, and raises the Setup dependency floor to 4.0.100.5 rather than retaining a pre-4.0.4 compatibility leg that the new package floor would make uninstallable. A daily canary floats Core and Setup so another upstream change can surface before pinned builds would find it. + +**Consequences:** Consumers pinned below the new dependency floor must update. The wrapper still reflects over internal AWS type and method names; replacing it with the public `AWSOptions.CreateServiceClient()` path was deferred because that path lacks an `IServiceProvider` overload and would require reworking options fallback and logger behavior. The canary is a mitigation, not proof that future SDK versions remain compatible. + +**Evidence:** [Bug #52](https://github.com/localstack-dotnet/localstack-dotnet-client/issues/52), [merged PR #53](https://github.com/localstack-dotnet/localstack-dotnet-client/pull/53), [floor/legacy-track decision commit](https://github.com/localstack-dotnet/localstack-dotnet-client/commit/8da194b2c6abb7b06b14128394a3fb5c9338d17a), and [current wrapper](../../src/LocalStack.Client.Extensions/AwsClientFactoryWrapper.cs). The earlier proposal to keep the old floor was not the merged decision. diff --git a/docs/adr/0003-edge-port-and-legacy-compatibility.md b/docs/adr/0003-edge-port-and-legacy-compatibility.md new file mode 100644 index 0000000..3695296 --- /dev/null +++ b/docs/adr/0003-edge-port-and-legacy-compatibility.md @@ -0,0 +1,9 @@ +# Use the LocalStack edge port by default and retain legacy ports + +Date: 2021-02-08 + +LocalStack introduced a shared edge endpoint, while existing client configurations still used per-service ports. The project made port 4566 and non-legacy routing the `ConfigOptions` defaults, but retained `UseLegacyPorts` as an explicit choice for older setups rather than removing their port mapping during the transition. This changed the usual network destination without forcing every existing configuration to change at once. + +**Scope:** The 2021 obsolete configuration constructor still had a legacy-port default; this record does not claim all historical constructors used edge routing. The 2023 change from `localhost` to `localhost.localstack.cloud` was a separate hostname change. [Issue #26](https://github.com/localstack-dotnet/localstack-dotnet-client/issues/26) proposes removing legacy ports, but an open proposal is not a reversal of this accepted decision. + +**Evidence:** [Merged PR #7](https://github.com/localstack-dotnet/localstack-dotnet-client/pull/7), [maintainer explanation in issue #5](https://github.com/localstack-dotnet/localstack-dotnet-client/issues/5#issuecomment-775340238), and the [current endpoint configuration](../../src/LocalStack.Client/Config.cs). diff --git a/docs/adr/README.md b/docs/adr/README.md new file mode 100644 index 0000000..1f0e9a7 --- /dev/null +++ b/docs/adr/README.md @@ -0,0 +1,29 @@ +# Architecture Decision Records + +Date: 2026-10-17 + +Each record in this directory describes one **accepted** decision: its context, the alternative that mattered, the chosen direction, and why. Name records `NNNN-slug.md` in sequence. The directory listing is the index; do not create a second list to maintain. + +Current rules live in [architecture](../architecture/) and [engineering](../engineering/). An ADR explains their historical rationale, not an additional current implementation or support policy. If a record and current source appear to disagree, check the decision's date and stop to resolve the discrepancy rather than treating the historical record as newer authority. + +## When to write an ADR + +All three must hold: + +1. **Hard to reverse** — changing course later carries real cost. +2. **Surprising without context** — a future reader would wonder "why did they do it this way?" +3. **A real trade-off** — genuine alternatives existed and one was chosen for specific reasons. + +If any leg is missing, skip the ADR: current conventions and process rules belong in the relevant `docs/engineering/` home, current architecture in `docs/architecture/`, and dated findings outside current canon. A merged change alone does not supply a reason or prove that an unmerged alternative was rejected. + +## Format + +```markdown +# Short title of the decision + +Date: YYYY-MM-DD + +One to three sentences: context, decision, and why. +``` + +Add considered alternatives, consequences, or supersession only when they carry information a future reader cannot infer from that paragraph. Use the date of the accepted decision, not the date on which someone wrote its retrospective record. A public ADR must explain its decision without access to private research; cite first-party public evidence directly. If dated internal evidence is useful, identify it by date and title rather than a private file path or identifier. diff --git a/docs/architecture/client-runtime.md b/docs/architecture/client-runtime.md new file mode 100644 index 0000000..c4f3e60 --- /dev/null +++ b/docs/architecture/client-runtime.md @@ -0,0 +1,19 @@ +# Client runtime and service mapping + +Date: 2026-10-17 + +The core package creates AWS SDK service clients configured for LocalStack. The [glossary](../../GLOSSARY.md) distinguishes an AWS service, an SDK client, and a configured LocalStack endpoint. + +## Endpoint catalog + +[`AwsServiceEndpointMetadata.All`](../../src/LocalStack.Client/Enums/AwsServiceEndpointMetadata.cs) is the catalog of service IDs, CLI names, catalog keys, and historical per-service ports. [`Config`](../../src/LocalStack.Client/Config.cs) derives an endpoint from that catalog and `ConfigOptions`: a host, HTTP or HTTPS scheme, and either the shared edge port (the default) or a legacy service port. The service ID lookup is an exact match against the AWS SDK's metadata value; a CLI name or enum spelling is not interchangeable with it. Ports are not unique service identifiers. + +The catalog is a mapping in **this library**, not a list of all AWS operations available in LocalStack. LocalStack's own service, edition, release, and operation coverage determines emulator capability. The official [LocalStack Python client](https://github.com/localstack/localstack-python-client) is an input when this catalog gains services, but a Python mapping is not itself proof of emulator behavior or of a mapping in this .NET release. A particular .NET release can create a LocalStack-configured client through `Session` for a service only after its own catalog contains the service ID. Until then, `Session` throws `NotSupportedClientException` for the missing mapping; that exception does **not** mean the emulator lacks the service. Functional-test counts do not define product support. Claims about an exact operation on a named LocalStack image or edition need separate evidence. + +## Client creation + +[`Session`](../../src/LocalStack.Client/Session.cs) accepts session options, an `IConfig` built from the endpoint catalog, and [`SessionReflection`](../../src/LocalStack.Client/Utils/SessionReflection.cs). Its interface-based path locates the AWS SDK implementation type by convention; its implementation-based path starts from the concrete type. Both inspect the SDK's private `serviceMetadata`, construct the corresponding `ClientConfig`, and create an SDK client with the configured credentials. + +The client configuration sets `UseHttp`, `ProxyHost`, and `ProxyPort` from the LocalStack settings. Where the configuration exposes `ForcePathStyle`, the reflection helper sets it for S3-compatible addressing. With `useServiceUrl: true`, `Session` sets the explicit `ServiceURL`; otherwise it requires a region name and sets `RegionEndpoint`. These are two configuration paths for a LocalStack-created client, **not** the application-level LocalStack/AWS mode switch. They do not by themselves prove where every later request travels. + +[`SessionStandalone`](../../src/LocalStack.Client/SessionStandalone.cs) creates this session without dependency injection. The optional Extensions package owns the application-level mode switch in [Extensions and composition](extensions-and-composition.md). The Core and Extensions reflection paths remain present on current `master`; see [platform and packaging](platform-and-packaging.md) for the Native AOT boundary. diff --git a/docs/architecture/extensions-and-composition.md b/docs/architecture/extensions-and-composition.md new file mode 100644 index 0000000..ea08b74 --- /dev/null +++ b/docs/architecture/extensions-and-composition.md @@ -0,0 +1,13 @@ +# Extensions and application composition + +Date: 2026-10-17 + +`LocalStack.Client.Extensions` integrates the core package with .NET configuration and dependency injection. The [client runtime](client-runtime.md) owns endpoint mapping and LocalStack client creation; this document owns application-level composition. + +[`AddLocalStack(IConfiguration)`](../../src/LocalStack.Client.Extensions/ServiceCollectionExtensions.cs) binds the `LocalStack` section to `LocalStackOptions`, `SessionOptions`, and `ConfigOptions`, including their non-public setters. It registers `IConfig` as transient and `ISessionReflection`, `ISession`, and `IAwsClientFactoryWrapper` as singletons. Registration prepares both client-creation paths; it does not itself enable LocalStack mode. + +`AddAwsService` registers an AWS service interface (singleton by default). When the configured `UseLocalStack` value is `true`, resolution calls `Session.CreateClientByInterface` and uses the LocalStack catalog. When it is `false`—the options default—resolution calls [`AwsClientFactoryWrapper`](../../src/LocalStack.Client.Extensions/AwsClientFactoryWrapper.cs) to create an ordinary AWS SDK client. `AddAWSServiceLocalStack` is an alias for the registration method, **not** an override of the mode switch. `TryAddAwsService` only adds a registration when one is absent. + +The AWS-mode wrapper uses reflection to find the SDK's non-public generic `ClientFactory`. It selects a constructor whose first parameter is `AWSOptions`, preferring fewer parameters, then supplies defaults for the remaining parameters and invokes the SDK factory method. This tolerates the optional constructor parameter introduced in `AWSSDK.Extensions.NETCore.Setup` 4.0.4, but it still depends on internal SDK type and method names. The accepted rationale for the compatibility choice lives in the [decision record](../adr/0002-aws-setup-constructor-compatibility.md). + +**Current overload caveat:** the shorter `TryAddAwsService(lifetime, useServiceUrl)` overload does not forward its `useServiceUrl` argument (`ServiceCollectionExtensions.cs:126-129`). The overload that accepts `AWSOptions?` does forward it. Do not describe URL selection as reliable across both overloads until the implementation changes. The `useServiceUrl` switch itself is distinct from `UseLocalStack`: it selects a client configuration path only after the LocalStack session is chosen. diff --git a/docs/architecture/platform-and-packaging.md b/docs/architecture/platform-and-packaging.md new file mode 100644 index 0000000..28d2bf7 --- /dev/null +++ b/docs/architecture/platform-and-packaging.md @@ -0,0 +1,26 @@ +# Platform and packaging boundary + +Date: 2026-10-17 + +The source of package versions, target frameworks, and dependencies is the project configuration, not a prose copy of their values: + +| Question | Owning file | +| --- | --- | +| Core and Extensions package versions | [`Directory.Build.props`](../../Directory.Build.props) | +| AWS SDK and other package versions; pinned versus floating canary track | [`Directory.Packages.props`](../../Directory.Packages.props) | +| Core target frameworks | [`LocalStack.Client.csproj`](../../src/LocalStack.Client/LocalStack.Client.csproj) | +| Extensions target frameworks and dependency on Core | [`LocalStack.Client.Extensions.csproj`](../../src/LocalStack.Client.Extensions/LocalStack.Client.Extensions.csproj) | +| Development SDK selection | [`global.json`](../../global.json) | +| Publication triggers and credentials mechanism | [GitHub Actions workflows](../../.github/workflows/) | + +At this revision Core explicitly targets `netstandard2.0`, `net472`, `net8.0`, and `net9.0`; Extensions targets `netstandard2.0`, `net8.0`, and `net9.0`. The AWS SDK v4 migration changed the explicit .NET Framework target from 4.6.2 to 4.7.2. The two packages can have different versions: the [changelog](../../CHANGELOG.md) records the Extensions-only 2.0.1 release. For an installation instruction, consult the actual package feed as well as the declared project version. + +## Native AOT and trimming + +The current Core and Extensions implementations reflect over AWS SDK internals. Their annotations warn consumers about dynamic code and trimming, and Extensions includes a linker descriptor for the internal AWS factory. Neither an annotation nor that descriptor establishes Native AOT compatibility for an application. Native AOT support is **not** a capability of the current published v2 line; the source-generator/`UnsafeAccessor` work in [draft PR #49](https://github.com/localstack-dotnet/localstack-dotnet-client/pull/49) is not part of this `master` revision. Do not treat a proposed release number as a delivery date. + +## Consumer README and release channels + +The [root README](../../README.md) is both the GitHub entry point and the source copied into each package project's tracked `README.md` by its `PreBuild` target. Those copies are package content, not independent documentation owners. Edit the root first and keep both copies byte-identical; a build can copy root content into them. + +The [CI workflow](../../.github/workflows/ci-cd.yml) publishes development packages to GitHub Packages after its configured matrix succeeds on a master push or eligible feature pull request. The scheduled [AWS SDK canary](../../.github/workflows/aws-sdk-canary.yml) tests newer Core and Setup versions; it does not publish packages. NuGet.org releases use the manually dispatched [publication workflow](../../.github/workflows/publish-nuget.yml), which requests an OIDC-based short-lived key. Workflow configuration describes intended execution, not evidence that a particular run or package publication succeeded. diff --git a/docs/engineering/deviation-protocol.md b/docs/engineering/deviation-protocol.md new file mode 100644 index 0000000..a816382 --- /dev/null +++ b/docs/engineering/deviation-protocol.md @@ -0,0 +1,12 @@ +# Resolve a documentation or source conflict + +Date: 2026-10-17 + +When two current statements disagree, **stop before implementing or copying either statement**. Identify the owner in [documentation ownership](documentation.md), pin the source revision and external dependency version if relevant, and classify the disagreement: + +1. **Stale explanation:** Current source and a dated decision agree, but another current document does not. Correct the owner's explanation and shorten the other location to a pointer. +2. **Implementation defect:** A current accepted contract and the code disagree. Report the observable difference; do not rewrite the contract to make the defect disappear. +3. **Undecided product policy:** Sources show what happens but do not decide what should be promised (for example, v1 support after its announced window or service behavior on a particular emulator edition). Ask the owner for the decision before stating it as current policy. +4. **Historical evidence:** A plan, draft, or handoff describes a different branch or a past decision. Keep its date and status visible; do not promote it into the current canon without an accepted decision event. + +After resolving the conflict, update the single current owner and any short relays in the same change. Keep unique, useful historical rationale in its decision record or dated evidence. Never silently restore a deleted agent guide, declare an unmerged branch implemented, suppress a failing check, or weaken a test to make the documents agree. diff --git a/docs/engineering/documentation.md b/docs/engineering/documentation.md new file mode 100644 index 0000000..730f8cd --- /dev/null +++ b/docs/engineering/documentation.md @@ -0,0 +1,30 @@ +# Documentation ownership + +Date: 2026-10-17 + +The public repository must explain its current behavior and accepted decisions without requiring access to a private archive. Give each current fact one owner. Other documents can briefly describe the fact for their reader and link to its owner; they must not become a second place to maintain the rule. + +| Question | Current owner | +| --- | --- | +| What does the core session do, and how is a service mapped? | [Client runtime](../architecture/client-runtime.md) | +| How does application configuration choose a LocalStack or ordinary AWS client? | [Extensions and composition](../architecture/extensions-and-composition.md) | +| What is shipped, on which frameworks, and what is the Native AOT boundary? | [Platform and packaging](../architecture/platform-and-packaging.md) | +| Which words distinguish the library, emulator, service identity, and client? | [Root glossary](../../GLOSSARY.md) | +| What checks and safety constraints apply to builds and tests? | [Quality gates](quality-gates.md); actual commands in the [build tasks](../../build/LocalStack.Build/CakeTasks/) and [workflows](../../.github/workflows/) | +| What happens when a current document conflicts with source or another rule? | [Deviation protocol](deviation-protocol.md) | +| Why was a hard-to-reverse, surprising trade-off accepted? | [Decision records](../adr/README.md) | +| How does a consumer install and configure the packages? | [Root README](../../README.md), also copied into both NuGet packages | +| What changed in a release? | [Changelog](../../CHANGELOG.md) | +| Which releases receive security patches, and how are vulnerabilities reported? | [Security policy](../../.github/SECURITY.md) | +| How does a contributor submit a change? | [Contribution guide](../../.github/CONTRIBUTING.md) and GitHub forms | +| Which package, SDK, framework, and CI values apply now? | `Directory.Build.props`, `Directory.Packages.props`, `global.json`, each `.csproj`, `BannedSymbols.txt`, and the relevant workflow—not a copied prose value | + +## Lifecycles + +- **Current architecture and engineering** describe the checked-in behavior. They change when the behavior changes. A `Date:` on these living documents is the latest substantive update, not a claim that the source was verified today by a live test. +- **ADRs** record accepted historical reasoning, including alternatives that were actually considered. Their `Date:` is the decision date. A later reversal updates current canon and deliberately supersedes or revises its ADR; Git history keeps the chain. +- **Release history** belongs to `CHANGELOG.md`. An announced future release or a tag is not a test result or proof of a package feed upload. +- **Research, temporary plans, handoffs, and ledgers** are dated evidence, not current policy. An organization-wide private archive is planned, but its repository, permissions, and retention are not established here. Until those decisions are made, locally ignored `artifacts/` files remain local work and are not a canonical source. Classify and validate each one before considering transfer; never treat a title such as “APPROVED” as acceptance without the corresponding decision event. +- **Open work** has no dedicated tracked roadmap in this revision. GitHub issues and the relevant source are leads; do not create a roadmap by copying checkboxes from an ignored plan. + +Useful information survives a documentation move: verify each unique claim, put it under its correct owner or retain it as dated evidence, then replace old current-text copies with short pointers. Shortening alone is not a reason to discard rationale. Public ADRs state their decision and reason in full; when internal evidence becomes available, cite it by date and title rather than linking private paths or numbering. `AGENTS.md` routes agents to the relevant public owner rather than repeating its contents. diff --git a/docs/engineering/quality-gates.md b/docs/engineering/quality-gates.md new file mode 100644 index 0000000..8816457 --- /dev/null +++ b/docs/engineering/quality-gates.md @@ -0,0 +1,24 @@ +# Quality gates and safe commands + +Date: 2026-10-17 + +The project uses xUnit tests and Cake Frosting build tasks. A command's success is evidence only for the projects, target frameworks, and dependencies it actually exercised. The [workflow YAML](../../.github/workflows/) owns CI triggers; [project files](../../tests/) and [Cake tasks](../../build/LocalStack.Build/CakeTasks/) own the runner mechanics. + +| Test layer | What it checks | Infrastructure | +| --- | --- | --- | +| Core and Extensions unit tests | Configuration, session and DI behavior | No LocalStack container | +| Integration tests | AWS SDK client construction and configuration across many services | No LocalStack API calls in the broad client-creation checks | +| Functional tests | Selected S3, DynamoDB, SQS, SNS, and CloudFormation operations | Testcontainers using LocalStack 3.7.1 and 4.6.0 | + +## Before running a task + +- The Cake default target depends on `tests`, and `BuildContext.SkipFunctionalTest` defaults to `true`. The usual build/test scripts therefore **do not run the functional suite** unless explicitly opted in; do not label an unqualified run “all tests.” +- **Do not opt into Cake functional tests on a shared Docker daemon.** [`TestTask`](../../build/LocalStack.Build/CakeTasks/TestTask.cs) lists *all* Docker containers, including stopped ones, and passes every returned ID to `DockerRm` without a project label filter. It can remove unrelated stopped containers and attempt to remove running ones. An isolated Docker daemon is a prerequisite for that Cake path. Running the functional test project directly avoids this particular Cake cleanup block, but still creates containers and requires its own environment check. +- On Unix, [`InitTask`](../../build/LocalStack.Build/CakeTasks/InitTask.cs) executes `git config --global core.autocrlf true`; `BuildTask` depends on it. A Cake build is not a read-only probe of the developer machine. +- `nuget-prepare-extensions` removes the Extensions project reference and adds a Core package reference to the tracked `.csproj`. Do not run it as a packaging dry run. An isolated `nuget-pack` task does not invoke that preparation automatically. The library projects' `PreBuild` targets also copy the root README and LICENSE into their package folders. + +## Evidence and CI + +The [main CI workflow](../../.github/workflows/ci-cd.yml) ignores Markdown-only changes on its master push and eligible pull-request triggers. The [dependency-review workflow](../../.github/workflows/dependency-review.yml) still triggers for eligible pull requests, so “all CI skips Markdown” is false. Documentation changes need local link, source-claim, and copy-consistency checks even when the main build workflow does not run. + +The badge-update step is `continue-on-error`, and its action logs a non-200 Gist response without turning that response into a failed step. Neither a badge nor a fixed test count in prose proves that the current revision passed. Report the actual command, target frameworks, result, and any tests deliberately not run. Do not infer NuGet publication, Native AOT support, or full LocalStack service behavior from a successful build or client-construction test. diff --git a/src/LocalStack.Client.Extensions/README.md b/src/LocalStack.Client.Extensions/README.md index c4fa022..d1986b8 100644 --- a/src/LocalStack.Client.Extensions/README.md +++ b/src/LocalStack.Client.Extensions/README.md @@ -2,27 +2,25 @@ [![Nuget](https://img.shields.io/nuget/dt/LocalStack.Client)](https://www.nuget.org/packages/LocalStack.Client/) [![NuGet v2.x](https://img.shields.io/endpoint?url=https%3A%2F%2Fyvfdbfas85.execute-api.eu-central-1.amazonaws.com%2Flive%2F%3Fpackage%3Dlocalstack.client%26source%3Dnuget%26track%3D2%26includeprerelease%3Dtrue%26label%3Dnuget)](https://www.nuget.org/packages/LocalStack.Client/) [![NuGet v1.x](https://img.shields.io/endpoint?url=https%3A%2F%2Fyvfdbfas85.execute-api.eu-central-1.amazonaws.com%2Flive%2F%3Fpackage%3Dlocalstack.client%26source%3Dnuget%26track%3D1%26includeprerelease%3Dtrue%26label%3Dnuget)](https://www.nuget.org/packages/LocalStack.Client/) [![CI/CD Pipeline](https://github.com/localstack-dotnet/localstack-dotnet-client/actions/workflows/ci-cd.yml/badge.svg)](https://github.com/localstack-dotnet/localstack-dotnet-client/actions/workflows/ci-cd.yml) [![Security](https://github.com/localstack-dotnet/localstack-dotnet-client/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/localstack-dotnet/localstack-dotnet-client/actions/workflows/github-code-scanning/codeql) [![Linux Tests](https://img.shields.io/endpoint?url=https://yvfdbfas85.execute-api.eu-central-1.amazonaws.com/live/badge/tests/linux?label=Tests)](https://yvfdbfas85.execute-api.eu-central-1.amazonaws.com/live/redirect/test-results/linux) -> **🚀 Quick Start**: `dotnet add package LocalStack.Client --version 2.0.0` (AWS SDK v4) | [Installation Guide](#-installation) | [GA Timeline](https://github.com/localstack-dotnet/localstack-dotnet-client/discussions/45) +> **🚀 Quick Start**: `dotnet add package LocalStack.Client --version 2.0.0` (AWS SDK v4) | [Package installation](#-package-installation) | [Migration context](https://github.com/orgs/localstack-dotnet/discussions/45) --- ## 🎉 What's New: AWS SDK v4 Support Available -**v2.0.0** is live with complete AWS SDK v4 support - easier migration than expected! +**v2.0.0** introduced AWS SDK for .NET v4 compatibility. Service reachability depends on this library's catalog mapping and the capabilities of the LocalStack release and edition you use. -- ✅ **1,168 tests passing** across all frameworks -- ✅ **Minimal breaking changes** (just .NET Framework 4.6.2 → 4.7.2 and AWS SDK v3 → v4) -- ✅ **Public APIs unchanged** - your code should work as-is! -- 📖 **[Read Full Roadmap](https://github.com/localstack-dotnet/localstack-dotnet-client/discussions/45)** +- đŸ§Ș Unit tests, AWS client-construction tests, and container-backed functional tests cover different parts of the library. See the [test and CI boundaries](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/docs/engineering/quality-gates.md) rather than relying on a fixed pass count. +- ⚠ **Migration changes** include .NET Framework 4.6.2 → 4.7.2 and AWS SDK v3 → v4; see the [changelog](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/CHANGELOG.md) before upgrading. **Version Strategy**: - v2.x (AWS SDK v4) active development on [master branch](https://github.com/localstack-dotnet/localstack-dotnet-client/tree/master) -- v1.x (AWS SDK v3) Available on [sdkv3-lts branch](https://github.com/localstack-dotnet/localstack-dotnet-client/tree/sdkv3-lts), maintenance until July 2026 +- v1.x (AWS SDK v3) remains available on the [sdkv3-lts branch](https://github.com/localstack-dotnet/localstack-dotnet-client/tree/sdkv3-lts), but support ended in July 2026. Use v2.x for maintained releases; see the [security policy](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/.github/SECURITY.md). ![LocalStack](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/assets/localstack-dotnet.png?raw=true) -Localstack.NET is an easy-to-use .NET client for [LocalStack](https://github.com/localstack/localstack), a fully functional local AWS cloud stack. The client library provides a thin wrapper around [aws-sdk-net](https://github.com/aws/aws-sdk-net) which automatically configures the target endpoints to use LocalStack for your local cloud application development. +LocalStack.NET is a .NET client library for [LocalStack](https://github.com/localstack/localstack), a local AWS cloud emulator. It configures AWS SDK clients for LocalStack when LocalStack mode is enabled; the same application registration can instead create ordinary AWS clients. ## 🚀 Platform Compatibility & Quality Status @@ -36,53 +34,8 @@ Localstack.NET is an easy-to-use .NET client for [LocalStack](https://github.com > **Heads‑up for `dotnet publish -p:PublishAot=true` / `PublishTrimmed=true` users** -- **v2.0.0 GA ships without Native AOT support.** - The current build still relies on reflection for some AWS SDK internals. - - Public entry points that touch reflection are tagged with - `[RequiresDynamicCode]` / `[RequiresUnreferencedCode]`. - - You’ll see IL3050 / IL2026 warnings at compile time (promoted to errors in a strict AOT publish). -- We already ship a linker descriptor with **`LocalStack.Client.Extensions`** - to keep the private `ClientFactory` machinery alive. **Nothing to configure for that part.** -- Until the reflection‑free, source‑generated path lands (work in progress in - [draft PR #49](https://github.com/localstack-dotnet/localstack-dotnet-client/pull/49) and tracked on - [roadmap #48](https://github.com/localstack-dotnet/localstack-dotnet-client/discussions/48)): - - 1. **Suppress** the warnings in your app *or* call only the APIs that don’t rely on reflection. - 2. Add a tiny **service‑specific** linker descriptor for every `AWSSDK.*` package you reference - (S3, DynamoDB, etc.). For example, for S3: - - ```xml - - - - - - - - - - - - - - - - ``` - - 3. Wire it into your project once: - - ```xml - - - - ``` - - 4. If you hit a runtime “missing member” error, ensure you’re on AWS SDK v4 **≄ 4.1.\*** and that - the concrete `AWSSDK.*` package you’re using is included in the descriptor above. - -> **Planned** – v2.1 will introduce an AOT‑friendly factory that avoids reflection entirely; once you -> migrate to that API these warnings and extra XML files go away. +- **The current v2 packages do not support Native AOT.** Both client-creation paths still use reflection over AWS SDK internals. Entry points carry `[RequiresDynamicCode]` and `[RequiresUnreferencedCode]` annotations where available, and Extensions embeds a linker descriptor for its internal AWS factory; neither guarantees that an application will trim or publish successfully with Native AOT. +- The reflection-free source-generator work is in [draft PR #49](https://github.com/localstack-dotnet/localstack-dotnet-client/pull/49), not in `master`. Do not suppress trimming/AOT warnings or adopt an unverified service descriptor on the assumption that this draft has shipped. See the [platform boundary](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/docs/architecture/platform-and-packaging.md). ### Build & Test Matrix @@ -96,7 +49,7 @@ Localstack.NET is an easy-to-use .NET client for [LocalStack](https://github.com ## Package Status -| Package | NuGet.org | GitHub Packages (Nightly) | +| Package | NuGet.org | GitHub Packages (development builds) | |---------|-----------|---------------------------| | **LocalStack.Client v1.x** | [![NuGet v1.x](https://img.shields.io/endpoint?url=https%3A%2F%2Fyvfdbfas85.execute-api.eu-central-1.amazonaws.com%2Flive%2Fbadge%2Fpackages%2Flocalstack.client%3Fsource%3Dnuget%26track%3D1%26label%3Dnuget)](https://www.nuget.org/packages/LocalStack.Client/) | [![Github v1.x](https://img.shields.io/endpoint?url=https%3A%2F%2Fyvfdbfas85.execute-api.eu-central-1.amazonaws.com%2Flive%2Fbadge%2Fpackages%2Flocalstack.client%3Fsource%3Dgithub%26track%3D1%26includeprerelease%3Dtrue%26label%3Dgithub)](https://github.com/localstack-dotnet/localstack-dotnet-client/pkgs/nuget/LocalStack.Client) | | **LocalStack.Client v2.x** | [![NuGet v2.x](https://img.shields.io/endpoint?url=https%3A%2F%2Fyvfdbfas85.execute-api.eu-central-1.amazonaws.com%2Flive%2Fbadge%2Fpackages%2Flocalstack.client%3Fsource%3Dnuget%26track%3D2%26includeprerelease%3Dtrue%26label%3Dnuget)](https://www.nuget.org/packages/LocalStack.Client/) | [![Github v2.x](https://img.shields.io/endpoint?url=https%3A%2F%2Fyvfdbfas85.execute-api.eu-central-1.amazonaws.com%2Flive%2Fbadge%2Fpackages%2Flocalstack.client%3Fsource%3Dgithub%26track%3D2%26includeprerelease%3Dtrue%26label%3Dgithub)](https://github.com/localstack-dotnet/localstack-dotnet-client/pkgs/nuget/LocalStack.Client) | @@ -125,7 +78,7 @@ Localstack.NET is an easy-to-use .NET client for [LocalStack](https://github.com - **Adaptable Environment Transition:** Easily switch between LocalStack and actual AWS services with minimal configuration changes. -- **Versatile .NET Compatibility:** Supports a broad spectrum of .NET versions, from .NET 9.0 and .NET Standard 2.0 to .NET Framework 4.6.2 and above. +- **Versatile .NET Compatibility:** Both packages target .NET 8, .NET 9, and .NET Standard 2.0; Core also has an explicit .NET Framework 4.7.2 target. See [platform and packaging](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/docs/architecture/platform-and-packaging.md) for the exact project targets. - **Reduced Learning Curve:** Offers a familiar interface tailored for LocalStack, ideal for developers acquainted with the AWS SDK for .NET. @@ -146,9 +99,9 @@ LocalStack.NET is available through multiple package sources to support differen To install the latest version of LocalStack.NET with AWS SDK v4 support, use the following command: ```bash -# Install v2.0.0 with AWS SDK v4 support +# Install the published v2 releases with AWS SDK v4 support dotnet add package LocalStack.Client --version 2.0.0 -dotnet add package LocalStack.Client.Extensions --version 2.0.0 +dotnet add package LocalStack.Client.Extensions --version 2.0.1 ``` #### Development Builds (GitHub Packages) @@ -183,14 +136,14 @@ public void ConfigureServices(IServiceCollection services) // Add framework services. services.AddMvc(); - services.AddLocalStack(Configuration) + services.AddLocalStack(Configuration); services.AddDefaultAWSOptions(Configuration.GetAWSOptions()); services.AddAwsService(); services.AddAwsService(); } ``` -The `AddLocalStack` method integrates LocalStack.NET into your application, and the `AddAwsService` method allows you to specify which AWS services you want to use with LocalStack. +`AddLocalStack` binds configuration and registers the library's services. `AddAwsService` registers the AWS service interface; `LocalStack:UseLocalStack` selects whether that interface is created through the LocalStack session or the ordinary AWS SDK factory. The default is `false`. See [client runtime and service support](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/docs/architecture/client-runtime.md) for what the endpoint catalog does—and does not—promise. (Alternatively, `AddAWSServiceLocalStack` method can be used to prevent mix-up with `AddAWSService`.) @@ -243,11 +196,7 @@ The `RegionName` is important as LocalStack creates resources based on the speci - **LocalStack Versions v2.0.1 - v2.2:** In versions v2.0.1 through v2.2 of LocalStack, the URL routing logic was changed, causing issues with SQS and S3 operations. Two issues were opened in LocalStack regarding this: [issue #8928](https://github.com/localstack/localstack/issues/8928) and [issue #8924](https://github.com/localstack/localstack/issues/8924). LocalStack addressed this problem with [PR #8962](https://github.com/localstack/localstack/pull/8962). Therefore, when using LocalStack.NET, either use version v2.0 of LocalStack (there are no issues with the v1 series as well) or the upcoming v2.3 version, or use the latest v3 series container from Docker Hub. -- **AWS_SERVICE_URL Environment Variable:** Unexpected behaviors might occur in LocalStack.NET when the `AWS_SERVICE_URL` environment variable is set. This environment variable is typically set by LocalStack in the container when using AWS Lambda, and AWS also uses this environment variable in the live environment. Soon, just like in LocalStack's official Python library, this environment variable will be prioritized by LocalStack.NET when configuring the LocalStack host, and there will be a general simplification in the configuration. You can follow this in the issues [issue #27](https://github.com/localstack-dotnet/localstack-dotnet-client/issues/27) and [issue #32](https://github.com/localstack-dotnet/localstack-dotnet-client/issues/32). You set the `AWS_SERVICE_URL` to empty string until this issue is resolved. - -```csharp -Environment.SetEnvironmentVariable("AWS_SERVICE_URL", string.Empty); -``` +- **Endpoint environment variables:** [Issue #27](https://github.com/localstack-dotnet/localstack-dotnet-client/issues/27#issuecomment-4937111791) records a 2026-07-10 SQS observation against Extensions 2.0.0. With `UseLocalStack=true`, a LocalStack proxy aimed at A and `AWS_ENDPOINT_URL` aimed at B sent traffic to A. With `UseLocalStack=false`, the proxy was unset and traffic followed B. This is a dated report, not a re-run against every SDK or service; the issue remains open and no general precedence fix is merged. `AWS_SERVICE_URL` can also appear in Lambda environments, but this library does not define a general override rule for it. Diagnose the actual SDK configuration before adopting an environment-variable workaround. - **IAmazonLambda Operations:** There's a general issue with `IAmazonLambda` operations. This matter is currently under investigation. @@ -273,6 +222,8 @@ Linux ./build.sh ``` +On Unix, this Cake script runs an initialization task that changes your global Git `core.autocrlf` setting. Read the [quality gates](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/docs/engineering/quality-gates.md) before running it on a shared machine. + ### Sandbox Applications The LocalStack .NET repository includes several sandbox console applications located in [tests/sandboxes](https://github.com/localstack-dotnet/localstack-dotnet-client/tree/master/tests/sandboxes). These applications serve both as testing tools and as examples. Refer to [the documentation](https://github.com/localstack-dotnet/localstack-dotnet-client/wiki/Developing#sandbox-applications) for more information @@ -301,8 +252,8 @@ Got questions or wild feature ideas? ## Changelog -Please refer to [`CHANGELOG.md`](CHANGELOG.md) to see the complete list of changes for each release. +Please refer to [`CHANGELOG.md`](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/CHANGELOG.md) to see the complete list of changes for each release. ## License -Licensed under MIT, see [LICENSE](LICENSE) for the full text. +Licensed under MIT, see [LICENSE](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/LICENSE) for the full text. diff --git a/src/LocalStack.Client/README.md b/src/LocalStack.Client/README.md index c4fa022..d1986b8 100644 --- a/src/LocalStack.Client/README.md +++ b/src/LocalStack.Client/README.md @@ -2,27 +2,25 @@ [![Nuget](https://img.shields.io/nuget/dt/LocalStack.Client)](https://www.nuget.org/packages/LocalStack.Client/) [![NuGet v2.x](https://img.shields.io/endpoint?url=https%3A%2F%2Fyvfdbfas85.execute-api.eu-central-1.amazonaws.com%2Flive%2F%3Fpackage%3Dlocalstack.client%26source%3Dnuget%26track%3D2%26includeprerelease%3Dtrue%26label%3Dnuget)](https://www.nuget.org/packages/LocalStack.Client/) [![NuGet v1.x](https://img.shields.io/endpoint?url=https%3A%2F%2Fyvfdbfas85.execute-api.eu-central-1.amazonaws.com%2Flive%2F%3Fpackage%3Dlocalstack.client%26source%3Dnuget%26track%3D1%26includeprerelease%3Dtrue%26label%3Dnuget)](https://www.nuget.org/packages/LocalStack.Client/) [![CI/CD Pipeline](https://github.com/localstack-dotnet/localstack-dotnet-client/actions/workflows/ci-cd.yml/badge.svg)](https://github.com/localstack-dotnet/localstack-dotnet-client/actions/workflows/ci-cd.yml) [![Security](https://github.com/localstack-dotnet/localstack-dotnet-client/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/localstack-dotnet/localstack-dotnet-client/actions/workflows/github-code-scanning/codeql) [![Linux Tests](https://img.shields.io/endpoint?url=https://yvfdbfas85.execute-api.eu-central-1.amazonaws.com/live/badge/tests/linux?label=Tests)](https://yvfdbfas85.execute-api.eu-central-1.amazonaws.com/live/redirect/test-results/linux) -> **🚀 Quick Start**: `dotnet add package LocalStack.Client --version 2.0.0` (AWS SDK v4) | [Installation Guide](#-installation) | [GA Timeline](https://github.com/localstack-dotnet/localstack-dotnet-client/discussions/45) +> **🚀 Quick Start**: `dotnet add package LocalStack.Client --version 2.0.0` (AWS SDK v4) | [Package installation](#-package-installation) | [Migration context](https://github.com/orgs/localstack-dotnet/discussions/45) --- ## 🎉 What's New: AWS SDK v4 Support Available -**v2.0.0** is live with complete AWS SDK v4 support - easier migration than expected! +**v2.0.0** introduced AWS SDK for .NET v4 compatibility. Service reachability depends on this library's catalog mapping and the capabilities of the LocalStack release and edition you use. -- ✅ **1,168 tests passing** across all frameworks -- ✅ **Minimal breaking changes** (just .NET Framework 4.6.2 → 4.7.2 and AWS SDK v3 → v4) -- ✅ **Public APIs unchanged** - your code should work as-is! -- 📖 **[Read Full Roadmap](https://github.com/localstack-dotnet/localstack-dotnet-client/discussions/45)** +- đŸ§Ș Unit tests, AWS client-construction tests, and container-backed functional tests cover different parts of the library. See the [test and CI boundaries](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/docs/engineering/quality-gates.md) rather than relying on a fixed pass count. +- ⚠ **Migration changes** include .NET Framework 4.6.2 → 4.7.2 and AWS SDK v3 → v4; see the [changelog](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/CHANGELOG.md) before upgrading. **Version Strategy**: - v2.x (AWS SDK v4) active development on [master branch](https://github.com/localstack-dotnet/localstack-dotnet-client/tree/master) -- v1.x (AWS SDK v3) Available on [sdkv3-lts branch](https://github.com/localstack-dotnet/localstack-dotnet-client/tree/sdkv3-lts), maintenance until July 2026 +- v1.x (AWS SDK v3) remains available on the [sdkv3-lts branch](https://github.com/localstack-dotnet/localstack-dotnet-client/tree/sdkv3-lts), but support ended in July 2026. Use v2.x for maintained releases; see the [security policy](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/.github/SECURITY.md). ![LocalStack](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/assets/localstack-dotnet.png?raw=true) -Localstack.NET is an easy-to-use .NET client for [LocalStack](https://github.com/localstack/localstack), a fully functional local AWS cloud stack. The client library provides a thin wrapper around [aws-sdk-net](https://github.com/aws/aws-sdk-net) which automatically configures the target endpoints to use LocalStack for your local cloud application development. +LocalStack.NET is a .NET client library for [LocalStack](https://github.com/localstack/localstack), a local AWS cloud emulator. It configures AWS SDK clients for LocalStack when LocalStack mode is enabled; the same application registration can instead create ordinary AWS clients. ## 🚀 Platform Compatibility & Quality Status @@ -36,53 +34,8 @@ Localstack.NET is an easy-to-use .NET client for [LocalStack](https://github.com > **Heads‑up for `dotnet publish -p:PublishAot=true` / `PublishTrimmed=true` users** -- **v2.0.0 GA ships without Native AOT support.** - The current build still relies on reflection for some AWS SDK internals. - - Public entry points that touch reflection are tagged with - `[RequiresDynamicCode]` / `[RequiresUnreferencedCode]`. - - You’ll see IL3050 / IL2026 warnings at compile time (promoted to errors in a strict AOT publish). -- We already ship a linker descriptor with **`LocalStack.Client.Extensions`** - to keep the private `ClientFactory` machinery alive. **Nothing to configure for that part.** -- Until the reflection‑free, source‑generated path lands (work in progress in - [draft PR #49](https://github.com/localstack-dotnet/localstack-dotnet-client/pull/49) and tracked on - [roadmap #48](https://github.com/localstack-dotnet/localstack-dotnet-client/discussions/48)): - - 1. **Suppress** the warnings in your app *or* call only the APIs that don’t rely on reflection. - 2. Add a tiny **service‑specific** linker descriptor for every `AWSSDK.*` package you reference - (S3, DynamoDB, etc.). For example, for S3: - - ```xml - - - - - - - - - - - - - - - - ``` - - 3. Wire it into your project once: - - ```xml - - - - ``` - - 4. If you hit a runtime “missing member” error, ensure you’re on AWS SDK v4 **≄ 4.1.\*** and that - the concrete `AWSSDK.*` package you’re using is included in the descriptor above. - -> **Planned** – v2.1 will introduce an AOT‑friendly factory that avoids reflection entirely; once you -> migrate to that API these warnings and extra XML files go away. +- **The current v2 packages do not support Native AOT.** Both client-creation paths still use reflection over AWS SDK internals. Entry points carry `[RequiresDynamicCode]` and `[RequiresUnreferencedCode]` annotations where available, and Extensions embeds a linker descriptor for its internal AWS factory; neither guarantees that an application will trim or publish successfully with Native AOT. +- The reflection-free source-generator work is in [draft PR #49](https://github.com/localstack-dotnet/localstack-dotnet-client/pull/49), not in `master`. Do not suppress trimming/AOT warnings or adopt an unverified service descriptor on the assumption that this draft has shipped. See the [platform boundary](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/docs/architecture/platform-and-packaging.md). ### Build & Test Matrix @@ -96,7 +49,7 @@ Localstack.NET is an easy-to-use .NET client for [LocalStack](https://github.com ## Package Status -| Package | NuGet.org | GitHub Packages (Nightly) | +| Package | NuGet.org | GitHub Packages (development builds) | |---------|-----------|---------------------------| | **LocalStack.Client v1.x** | [![NuGet v1.x](https://img.shields.io/endpoint?url=https%3A%2F%2Fyvfdbfas85.execute-api.eu-central-1.amazonaws.com%2Flive%2Fbadge%2Fpackages%2Flocalstack.client%3Fsource%3Dnuget%26track%3D1%26label%3Dnuget)](https://www.nuget.org/packages/LocalStack.Client/) | [![Github v1.x](https://img.shields.io/endpoint?url=https%3A%2F%2Fyvfdbfas85.execute-api.eu-central-1.amazonaws.com%2Flive%2Fbadge%2Fpackages%2Flocalstack.client%3Fsource%3Dgithub%26track%3D1%26includeprerelease%3Dtrue%26label%3Dgithub)](https://github.com/localstack-dotnet/localstack-dotnet-client/pkgs/nuget/LocalStack.Client) | | **LocalStack.Client v2.x** | [![NuGet v2.x](https://img.shields.io/endpoint?url=https%3A%2F%2Fyvfdbfas85.execute-api.eu-central-1.amazonaws.com%2Flive%2Fbadge%2Fpackages%2Flocalstack.client%3Fsource%3Dnuget%26track%3D2%26includeprerelease%3Dtrue%26label%3Dnuget)](https://www.nuget.org/packages/LocalStack.Client/) | [![Github v2.x](https://img.shields.io/endpoint?url=https%3A%2F%2Fyvfdbfas85.execute-api.eu-central-1.amazonaws.com%2Flive%2Fbadge%2Fpackages%2Flocalstack.client%3Fsource%3Dgithub%26track%3D2%26includeprerelease%3Dtrue%26label%3Dgithub)](https://github.com/localstack-dotnet/localstack-dotnet-client/pkgs/nuget/LocalStack.Client) | @@ -125,7 +78,7 @@ Localstack.NET is an easy-to-use .NET client for [LocalStack](https://github.com - **Adaptable Environment Transition:** Easily switch between LocalStack and actual AWS services with minimal configuration changes. -- **Versatile .NET Compatibility:** Supports a broad spectrum of .NET versions, from .NET 9.0 and .NET Standard 2.0 to .NET Framework 4.6.2 and above. +- **Versatile .NET Compatibility:** Both packages target .NET 8, .NET 9, and .NET Standard 2.0; Core also has an explicit .NET Framework 4.7.2 target. See [platform and packaging](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/docs/architecture/platform-and-packaging.md) for the exact project targets. - **Reduced Learning Curve:** Offers a familiar interface tailored for LocalStack, ideal for developers acquainted with the AWS SDK for .NET. @@ -146,9 +99,9 @@ LocalStack.NET is available through multiple package sources to support differen To install the latest version of LocalStack.NET with AWS SDK v4 support, use the following command: ```bash -# Install v2.0.0 with AWS SDK v4 support +# Install the published v2 releases with AWS SDK v4 support dotnet add package LocalStack.Client --version 2.0.0 -dotnet add package LocalStack.Client.Extensions --version 2.0.0 +dotnet add package LocalStack.Client.Extensions --version 2.0.1 ``` #### Development Builds (GitHub Packages) @@ -183,14 +136,14 @@ public void ConfigureServices(IServiceCollection services) // Add framework services. services.AddMvc(); - services.AddLocalStack(Configuration) + services.AddLocalStack(Configuration); services.AddDefaultAWSOptions(Configuration.GetAWSOptions()); services.AddAwsService(); services.AddAwsService(); } ``` -The `AddLocalStack` method integrates LocalStack.NET into your application, and the `AddAwsService` method allows you to specify which AWS services you want to use with LocalStack. +`AddLocalStack` binds configuration and registers the library's services. `AddAwsService` registers the AWS service interface; `LocalStack:UseLocalStack` selects whether that interface is created through the LocalStack session or the ordinary AWS SDK factory. The default is `false`. See [client runtime and service support](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/docs/architecture/client-runtime.md) for what the endpoint catalog does—and does not—promise. (Alternatively, `AddAWSServiceLocalStack` method can be used to prevent mix-up with `AddAWSService`.) @@ -243,11 +196,7 @@ The `RegionName` is important as LocalStack creates resources based on the speci - **LocalStack Versions v2.0.1 - v2.2:** In versions v2.0.1 through v2.2 of LocalStack, the URL routing logic was changed, causing issues with SQS and S3 operations. Two issues were opened in LocalStack regarding this: [issue #8928](https://github.com/localstack/localstack/issues/8928) and [issue #8924](https://github.com/localstack/localstack/issues/8924). LocalStack addressed this problem with [PR #8962](https://github.com/localstack/localstack/pull/8962). Therefore, when using LocalStack.NET, either use version v2.0 of LocalStack (there are no issues with the v1 series as well) or the upcoming v2.3 version, or use the latest v3 series container from Docker Hub. -- **AWS_SERVICE_URL Environment Variable:** Unexpected behaviors might occur in LocalStack.NET when the `AWS_SERVICE_URL` environment variable is set. This environment variable is typically set by LocalStack in the container when using AWS Lambda, and AWS also uses this environment variable in the live environment. Soon, just like in LocalStack's official Python library, this environment variable will be prioritized by LocalStack.NET when configuring the LocalStack host, and there will be a general simplification in the configuration. You can follow this in the issues [issue #27](https://github.com/localstack-dotnet/localstack-dotnet-client/issues/27) and [issue #32](https://github.com/localstack-dotnet/localstack-dotnet-client/issues/32). You set the `AWS_SERVICE_URL` to empty string until this issue is resolved. - -```csharp -Environment.SetEnvironmentVariable("AWS_SERVICE_URL", string.Empty); -``` +- **Endpoint environment variables:** [Issue #27](https://github.com/localstack-dotnet/localstack-dotnet-client/issues/27#issuecomment-4937111791) records a 2026-07-10 SQS observation against Extensions 2.0.0. With `UseLocalStack=true`, a LocalStack proxy aimed at A and `AWS_ENDPOINT_URL` aimed at B sent traffic to A. With `UseLocalStack=false`, the proxy was unset and traffic followed B. This is a dated report, not a re-run against every SDK or service; the issue remains open and no general precedence fix is merged. `AWS_SERVICE_URL` can also appear in Lambda environments, but this library does not define a general override rule for it. Diagnose the actual SDK configuration before adopting an environment-variable workaround. - **IAmazonLambda Operations:** There's a general issue with `IAmazonLambda` operations. This matter is currently under investigation. @@ -273,6 +222,8 @@ Linux ./build.sh ``` +On Unix, this Cake script runs an initialization task that changes your global Git `core.autocrlf` setting. Read the [quality gates](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/docs/engineering/quality-gates.md) before running it on a shared machine. + ### Sandbox Applications The LocalStack .NET repository includes several sandbox console applications located in [tests/sandboxes](https://github.com/localstack-dotnet/localstack-dotnet-client/tree/master/tests/sandboxes). These applications serve both as testing tools and as examples. Refer to [the documentation](https://github.com/localstack-dotnet/localstack-dotnet-client/wiki/Developing#sandbox-applications) for more information @@ -301,8 +252,8 @@ Got questions or wild feature ideas? ## Changelog -Please refer to [`CHANGELOG.md`](CHANGELOG.md) to see the complete list of changes for each release. +Please refer to [`CHANGELOG.md`](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/CHANGELOG.md) to see the complete list of changes for each release. ## License -Licensed under MIT, see [LICENSE](LICENSE) for the full text. +Licensed under MIT, see [LICENSE](https://github.com/localstack-dotnet/localstack-dotnet-client/blob/master/LICENSE) for the full text.