Skip to content

feat: CommunityToolkit.Aspire.Hosting.Floci — Floci cloud emulator hosing integration#1479

Open
edmondshtogu wants to merge 4 commits into
CommunityToolkit:mainfrom
edmondshtogu:floci
Open

feat: CommunityToolkit.Aspire.Hosting.Floci — Floci cloud emulator hosing integration#1479
edmondshtogu wants to merge 4 commits into
CommunityToolkit:mainfrom
edmondshtogu:floci

Conversation

@edmondshtogu

Copy link
Copy Markdown
Contributor

Closes floci-io/floci#1242

Adds CommunityToolkit.Aspire.Hosting.Floci — a hosting integration for Floci, a family of high-performance local cloud emulators (floci/floci for AWS, floci/floci-az for Azure, floci/floci-gcp for GCP) that run as containers inside the Aspire AppHost.

What's included

Core integration (src/CommunityToolkit.Aspire.Hosting.Floci/)

  • AddFlociAws(name, port?, defaultRegion?, defaultAccountId?) — adds the Floci AWS container with an HTTP health check at /_floci/info
  • AddFlociAzure(name, port?) — adds the Floci Azure container (floci/floci-az), health check at /_floci/health
  • AddFlociGcp(name, port?, defaultProjectId?) — adds the Floci GCP container (floci/floci-gcp), health check at /_floci-gcp/health
  • All three cloud resources share a common abstract base (FlociContainerResource) that holds endpoint/connection-string plumbing, so Host, Port, PrimaryEndpoint, and ConnectionStringExpression are implemented once and inherited — not duplicated per cloud
  • WithReference automatically injects the standard ConnectionStrings__<name> plus provider-specific env vars via a BeforeStartEvent subscriber; host processes receive localhost:{port}, containers receive host.docker.internal:{port}:
    • AWS: AWS_ENDPOINT_URL, AWS_DEFAULT_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
    • Azure: AZURE_STORAGE_CONNECTION_STRING (well-known devstoreaccount1 dev credentials)
    • GCP: PUBSUB_EMULATOR_HOST, FIRESTORE_EMULATOR_HOST, DATASTORE_EMULATOR_HOST, STORAGE_EMULATOR_HOST, SECRET_MANAGER_EMULATOR_HOST, GOOGLE_CLOUD_PROJECT, CLOUDSDK_CORE_PROJECT
  • WithDataVolume / WithDataBindMount — switches Floci from in-memory to persistent storage mode; implemented once and shared across all three clouds
  • WithDockerSocket — mounts the Docker socket so Lambda / Azure Functions / Cloud Run and other container-backed services can launch sibling containers; adds --add-host=host.docker.internal:host-gateway to container dependents; shared across all three clouds
  • WithConfigFile(hostPath) — bind-mounts a Quarkus application.yml override at /deployments/config/application.yml for advanced configuration (AWS only — Azure/GCP images don't expose this)

Floci UI web console (WithFlociUI / WithPluggedCloud)

  • WithFlociUI(configureContainer?, containerName?) — available on all three cloud resource types, adds a single shared FlociUIContainerResource running docker.io/floci/floci-ui:0.2.0:
    • Wired to the creating cloud's endpoint over the container network (FLOCI_ENDPOINT for AWS, FLOCI_AZURE_ENDPOINT for Azure, FLOCI_GCP_ENDPOINT for GCP)
    • HTTP health check on /; excluded from manifest (ExcludeFromManifest())
    • Idempotent per creating cloud resource: calling WithFlociUI twice re-configures the existing UI container instead of adding a duplicate
  • WithPluggedCloud(cloud) — attaches an additional cloud resource to an already-created UI console, so one console can browse AWS + Azure + GCP at once instead of spinning up three separate UI containers. In C# this is a single overloaded method name; the generated TypeScript bindings expose it as withPluggedCloudAws / withPluggedCloudAzure / withPluggedCloudGcp since the polyglot export generator needs distinct names when all three overloads share the same target type
  • WithHostPort(int?) on the UI resource builder to pin the host port
  • image

Examples and tests

  • C# and TypeScript AppHosts each provision all three clouds plus a single shared UI console (aws.WithFlociUI(configureContainer: ui => { ui.WithPluggedCloud(azure); ui.WithPluggedCloud(gcp); }))
  • The example ApiService exercises all three clouds end-to-end: S3 (AWS SDK), Blob Storage (Azure SDK), and Cloud Storage (GCP SDK), each with its own health check (floci-s3, floci-azure-blob, floci-gcp-storage) and a hosted service that creates a demo bucket/container on startup
  • 41 tests across 6 test classes: resource creation/env-var coverage for each cloud (AWS/Azure/GCP), the shared multi-cloud UI (WithPluggedCloud attaches correctly, single UI container, correct env vars per attached cloud), the TypeScript AppHost, and Docker-gated AppHost integration tests asserting all three cloud resources and the UI resource become healthy
  • README with C#/TS examples for every extension method across all three clouds, including the standard ConnectionStrings__<name> behavior alongside each cloud's provider-specific env vars

PR Checklist

  • Created a feature/dev branch in your fork (vs. submitting directly from a commit on main)
  • Based off latest main branch of toolkit
  • PR doesn't include merge commits (always rebase on top of our main, if needed)
  • New integration
    • Docs are written
    • Added description of major feature to project description for NuGet package (4000 total character limit, so don't push entire description over that)
  • Tests for the changes have been added (for bug fixes / features) (if applicable)
  • Contains NO breaking changes
  • Every new API (including internal ones) has full XML docs
  • Code follows all style conventions

Other information

  • This integration does not support TLS — none of the three Floci images (floci/floci, floci/floci-az, floci/floci-gcp) expose certificate-based configuration the way the earlier AWS-only prototype assumed, so that support was removed rather than shipped half-working
  • AWS_ENDPOINT_URL is the standard SDK v4 env var; no AmazonS3Config.RegionEndpoint should be set alongside ServiceURL (triggers a NullReferenceException in the v4 endpoint rule engine — documented in the example)
  • GCP's StorageClient is built with EmulatorDetection.EmulatorOnly so it reads STORAGE_EMULATOR_HOST and skips real GCP credential resolution entirely
  • The ASPIREATS001 experimental diagnostic (polyglot export attributes) is suppressed at file level in the hosting extension files

@github-actions

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/CommunityToolkit/Aspire/main/eng/scripts/dogfood-pr.sh | bash -s -- 1479

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/CommunityToolkit/Aspire/main/eng/scripts/dogfood-pr.ps1) } 1479"

@edmondshtogu
edmondshtogu marked this pull request as ready for review July 23, 2026 12:07
@edmondshtogu

Copy link
Copy Markdown
Contributor Author

@aaronpowell in addition to this feature I had to fix the restore issue for the security vulnerabilities caused by System.Security.Cryptography.Xml version 8.0.3 (by overriding the version with 8.0.4).

The PR is ready for your review, so please take a look and let me know if you have any concern.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] Add Aspire hosting support (Aspire.Hosting.Floci)

2 participants