Skip to content

Conversation

@Blind-Striker
Copy link
Contributor

@Blind-Striker Blind-Striker commented Nov 4, 2025

Pull Request: Custom Container Registry Support & Lifetime Default Alignment

📝 Description

What does this PR do?

This PR introduces two major improvements:

  1. Custom Container Registry Support: Adds the ability to pull LocalStack container images from private registries (Artifactory, Azure Container Registry, AWS ECR, GitHub Container Registry, etc.) to support enterprise environments with strict security requirements.

  2. Lifetime Default Alignment: Changes the default container lifetime from Persistent to Session to align with .NET Aspire's conventions and our own documentation recommendations.

Related Issue(s):

🔄 Type of Change

  • ✨ New feature (non-breaking change that adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 📚 Documentation update
  • 🧪 Test improvements

🎯 Aspire Compatibility

  • Compatible with .NET Aspire 9.x
  • Supports both .NET 8.0 and .NET 9.0
  • Follows Aspire.Hosting.AWS patterns
  • Works with existing AWS integrations

🧪 Testing

How has this been tested?

  • Unit tests added/updated
    • Added 6 new tests for container registry properties
    • Added 3 new tests for default lifetime behavior
    • Updated existing test to expect Session as default
  • Manual testing with playground examples
  • Tested with LocalStack container
  • Tested across multiple .NET versions

Test Environment:

  • LocalStack Version: 4.10.0
  • .NET Aspire Version: 9.5.2
  • .NET Versions Tested: .NET 8.0, .NET 9.0
  • Operating Systems: Windows (development), CI will test Linux

📚 Documentation

  • Code is self-documenting with clear naming
  • XML documentation comments added/updated
    • Enhanced Lifetime property docs with detailed behavior descriptions
    • Enhanced Port property docs showing interaction with Lifetime
    • Added comprehensive docs for ContainerRegistry, ContainerImage, ContainerImageTag
  • README.md updated
    • Updated Container Configuration section
    • Added private registry usage example
    • Updated Available Options with new properties
  • CONFIGURATION.md updated
    • Added Quick Reference table entries
    • Added "Port Configuration" section with default behaviors
    • Added "Custom Container Registry" section with:
      • Why organizations need it
      • Configuration properties explanation
      • Common scenarios (Artifactory, ACR, ECR, GHCR)
      • Authentication guidance
      • Backward compatibility notes
    • Updated Container Lifetime section to show Session as default
    • Updated all Configuration Patterns to reflect new defaults
  • Breaking changes documented

✅ Code Quality Checklist

  • Code follows project coding standards
  • No new analyzer warnings introduced
  • All tests pass locally (309 tests passing)
  • No merge conflicts
  • Branch is up to date with target branch
  • Commit messages follow Conventional Commits

🔍 Additional Notes

Breaking Changes

Lifetime Default Change: PersistentSession

Impact:

  • Containers will now be cleaned up when the application stops (instead of persisting)
  • Dynamic port assignment by default for Session lifetime (instead of static port 4566)
  • Better CI/CD experience out of the box
  • Aligns with Aspire's conventions (Session is Aspire's default)

Migration Path:
Users who want the previous Persistent behavior can explicitly set:

builder.AddLocalStack(configureContainer: container =>
{
    container.Lifetime = ContainerLifetime.Persistent;
});

Rationale:

  • Aspire's default for containers is Session
  • Our own documentation already recommended Session while defaulting to Persistent (confusing)
  • LocalStack is a development/testing tool, not a database - ephemeral is more appropriate
  • Better for CI/CD by default (clean state, no port conflicts)

Performance Impact

Positive:

  • Session lifetime with dynamic ports eliminates port conflict issues in parallel test scenarios
  • No performance degradation from new features

Neutral:

  • Custom registry properties are optional with same defaults as before
  • Existing users not using registries see zero impact

Dependencies

No new dependencies added. All changes use existing Aspire APIs.

🎯 Reviewer Focus Areas

Please pay special attention to:

  • Breaking changes - Lifetime default change is well-documented and justified
  • Test coverage - 9 new tests added covering all scenarios
  • Documentation completeness - Extensive updates to README and CONFIGURATION
  • Aspire integration patterns - Follows Aspire conventions consistently
  • LocalStack compatibility - Works with all LocalStack versions
  • Backward compatibility - All new properties are optional with sensible defaults

📸 Screenshots/Examples

Custom Container Registry Usage

// Example: Using Artifactory
var builder = DistributedApplication.CreateBuilder(args);

var localstack = builder.AddLocalStack(configureContainer: container =>
{
    // Pull from private Artifactory registry
    container.ContainerRegistry = "artifactory.company.com";
    container.ContainerImage = "docker-local/localstack/localstack";
    container.ContainerImageTag = "4.10.0";
});

builder.UseLocalStack(localstack);
builder.Build().Run();

Azure Container Registry

var localstack = builder.AddLocalStack(configureContainer: container =>
{
    container.ContainerRegistry = "mycompany.azurecr.io";
    container.ContainerImage = "localstack/localstack";
    container.ContainerImageTag = "4.10.0";
});

AWS ECR

var localstack = builder.AddLocalStack(configureContainer: container =>
{
    container.ContainerRegistry = "123456789012.dkr.ecr.us-west-2.amazonaws.com";
    container.ContainerImage = "localstack/localstack";
    container.ContainerImageTag = "4.10.0";
});

Migration: Persistent Lifetime

// For users who want the previous Persistent behavior
var localstack = builder.AddLocalStack(configureContainer: container =>
{
    container.Lifetime = ContainerLifetime.Persistent;  // Explicitly set
});

📊 Test Results

All 43 related unit tests passing on both .NET 8.0 and .NET 9.0:

  • ✅ LocalStackContainerOptionsTests: 15 tests (including 6 new registry tests)
  • ✅ AddLocalStackTests: 28 tests (including 5 new registry integration tests)
  • ✅ All existing tests updated for the new Session default

🔗 Related Work

This PR builds on:

🎯 Follow-up Items

None. This PR is complete and ready for review.


By submitting this pull request, I confirm that:

  • I have read and agree to the project's Code of Conduct
  • I understand that this contribution may be subject to the .NET Foundation CLA
  • My contribution is licensed under the same terms as the project (MIT License)

Note

Adds registry/image/tag overrides for the LocalStack container and changes the default container lifetime to Session with updated port behavior and docs.

  • Library/API:
    • LocalStackContainerOptions: default Lifetime changed to Session; added ContainerRegistry, ContainerImage, ContainerImageTag; expanded XML docs; clarified Port behavior.
    • AddLocalStack(...): honors custom image registry/image/tag; endpoint port selection updated to depend on Lifetime unless Port is set.
  • Docs:
    • README and docs/CONFIGURATION.md updated: Session as default; detailed port behavior; new custom registry/image/tag configuration with examples and scenarios; configuration patterns adjusted.
  • Tests:
    • New/updated unit tests covering Session default, image registry/image/tag overrides, and endpoint port behavior.

Written by Cursor Bugbot for commit b4692c5. This will update automatically on new commits. Configure here.

…t with Aspire

BREAKING CHANGE: Default container lifetime changed from Persistent to Session to align with Aspire conventions.

- Add ContainerRegistry, ContainerImage, ContainerImageTag properties to LocalStackContainerOptions
- Support pulling LocalStack images from private registries (Artifactory, ACR, ECR, GHCR)
- All new properties optional with backward-compatible defaults (docker.io/localstack/localstack)
- Change default Lifetime from Persistent to Session (matches Aspire's default)
- Update port behavior documentation to reflect Session uses dynamic ports by default
- Add comprehensive unit tests for new registry properties and default behavior
- Update README.md and CONFIGURATION.md with usage examples and configuration patterns
- Add registry authentication guidance for various providers

Migration: Users relying on Persistent lifetime should explicitly set:
container.Lifetime = ContainerLifetime.Persistent;

Fixes  #16
@Blind-Striker Blind-Striker added this to the 9.5.3 milestone Nov 4, 2025
@Blind-Striker Blind-Striker requested a review from Copilot November 4, 2025 13:46
@Blind-Striker Blind-Striker self-assigned this Nov 4, 2025
@Blind-Striker Blind-Striker added the enhancement New feature or request label Nov 4, 2025
@github-actions
Copy link

github-actions bot commented Nov 4, 2025

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR updates the default container lifetime for LocalStack from Persistent to Session and adds support for customizing the container image source (registry, image name, and tag). The Session lifetime better aligns with Aspire's conventions and provides cleaner state guarantees for CI/CD and integration testing scenarios.

Key changes:

  • Changed default ContainerLifetime from Persistent to Session with updated documentation explaining the behavioral differences
  • Added three new properties (ContainerRegistry, ContainerImage, ContainerImageTag) to LocalStackContainerOptions for custom image sources
  • Updated port mapping behavior to use dynamic ports by default with Session lifetime and static port 4566 with Persistent lifetime

Reviewed Changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/Aspire.Hosting.LocalStack/Container/LocalStackContainerOptions.cs Added three new nullable properties for custom container registry/image configuration with default values handled via null-coalescing
src/Aspire.Hosting.LocalStack/LocalStackResourceBuilderExtensions.cs Updated to use custom container image properties with fallback to defaults; reordered port and targetPort parameters in WithHttpEndpoint
tests/Aspire.Hosting.LocalStack.Unit.Tests/Container/LocalStackContainerOptionsTests.cs Updated default lifetime assertion and added tests for new container image properties
tests/Aspire.Hosting.LocalStack.Unit.Tests/Extensions/ResourceBuilderExtensionsTests/AddLocalStackTests.cs Added comprehensive tests verifying default and custom container image behavior
docs/CONFIGURATION.md Extensive documentation updates explaining lifetime behavior, port mapping, and custom registry usage with examples
README.md Updated to reflect new default lifetime and added documentation for new configuration properties

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@Blind-Striker Blind-Striker merged commit aa453b5 into master Nov 4, 2025
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants