microsoft / microsoft/aspire

Publishers crash or silently drop resources when references cross resource boundaries

Open
#15,900 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

area-app-model
Dominant language
C#
Stars
6.3k
Forks
991
Avg merge
2d 12h
Merged PRs (30d)
201

Description

## Problem

Publishers crash or silently drop resources when references cross resource boundaries. This affects **all** compute environment implementations:

- **Docker Compose** (`DockerComposeInfrastructure`)
- **Azure Container Apps** (`AzureContainerAppsInfrastructure`)
- **Azure App Service**
- **Kubernetes**
- **Any 3rd-party implementation** that follows the same `BeforeStart` + `GetComputeResources` + `ResourceMapping` pattern

The root pattern is broken and needs to change.

### Root cause

All publishers follow the same pattern:

1. Subscribe to `BeforeStartEvent`
2. Iterate `GetComputeResources()` (which filters out build-only, excluded, cross-environment resources)
3. Build a `ResourceMapping` dictionary from only those filtered resources
4. Resolve environment variables — which can reference ANY resource, including filtered ones
5. 💥 `KeyNotFoundException` when a callback references a resource not in the mapping

`GetComputeResources()` makes a premature decision about which resources matter. It conflates "should this resource be deployed" with "should this resource exist in the resolution graph." These are different questions.

### Affected publishers

| Publisher | Mapping | Crash site |
|-----------|---------|------------|
| Docker Compose | `DockerComposeEnvironmentResource.ResourceMapping` | `DockerComposeServiceResourceExtensions.ProcessValueAsync:22` |
| Azure Container Apps | `ContainerAppEnvironmentContext._containerApps` | `BaseContainerAppContext:227` |
| Azure App Service | Similar pattern | Similar crash |
| Kubernetes | Similar pattern | Similar crash |
| 3rd-party | Anyone using `GetComputeResources()` | Same |

### Scenario 1: Build-only container referenced by another resource

A JavaScript app without a `PublishAs*` method is build-only. When another resource references it, the publisher crashes.

```csharp
var frontend = builder.AddViteApp("frontend", "./frontend")
.WithHttpEndpoint(name: "http", targetPort: 3000);

builder.AddContainer("api", "apiimage")
.WithReference(frontend.GetEndpoint("http"));
```

**Result**: `KeyNotFoundException` during `publish-compose` step.

### Scenario 2: Excluded resource referenced by another resource

```csharp
var excluded = builder.AddContainer("auth", "authimage")
.WithHttpEndpoint(name: "http", targetPort: 8080)
.ExcludeFromManifest();

builder.AddContainer("api", "apiimage")
.WithReference(excluded.GetEndpoint("http"));
```

**Result**: `KeyNotFoundException` — excluded resource not in mapping.

### Scenario 3: Cross-environment resource referenced

```csharp
var compose1 = builder.AddDockerComposeEnvironment("compose1");
var compose2 = builder.AddDockerComposeEnvironment("compose2");

var db = builder.AddContainer("db", "postgres")
.WithHttpEndpoint(name: "http", targetPort: 5432)
.WithComputeEnvironment(compose2);

builder.AddContainer("api", "apiimage")
.WithComputeEnvironment(compose1)
.WithReference(db.GetEndpoint("http"));
```

**Result**: `KeyNotFoundException` — `db` not in `compose1`'s mapping.

### Scenario 4: Build-only container with no consumer (silent omission)

```csharp
// User forgot .PublishAsStaticWebsite()
builder.AddViteApp("frontend", "./frontend")
.WithExternalHttpEndpoints();

builder.AddContainer("api", "apiimage");
```

**Result**: `PIPELINE SUCCEEDED` ✅ but `frontend` is silently missing from output. No error.

### Proposed fix

**Dependent on #11787** — infrastructure processing runs in `BeforeStartEvent`, which is too early.

We need to change the pattern that all publishers follow:

1. **Move infrastructure processing from `BeforeStart` into pipeline steps** — proper ordering, other subscribers can add annotations first
2. **Build the full resource mapping** — ALL resources get registered (endpoints only), not just compute resources. References never crash.
3. **Separate "resolvable" from "deployable"** — all resources are resolvable (in the mapping), only compute resources are deployable (get `DeploymentTargetAnnotation`, appear in output)
4. **Validate the resource graph** — after resolution, check for invalid states:
- Build-only resource not consumed and not explicitly excluded → error with actionable message
- Excluded resource referenced by a deployable resource → error with actionable message
5. **Update all publishers** — Docker Compose first, then replicate to ACA, App Service, K8s
6. **Document the pattern** for 3rd-party implementors

### Test cases

4 test cases on branch `davidfowl/fix-resource-exclusion` in `DockerComposeResourceExclusionTests.cs`:

- `ReferencedResourceExcludedFromPublish_ShouldNotCrash`
- `ReferencedResourceTargetingDifferentEnvironment_ShouldNotCrash`
- `ReferencedBuildOnlyContainer_ShouldNotCrash`
- `UnreferencedBuildOnlyContainer_ShouldFailWithClearError`

### Related

- Depends on: #11787 (BeforeStartEvent is too early for infrastructure processing)
- JavaScript pits of failure: https://aspire.dev/deployment/javascript-apps/#pits-of-failure
- Branch with WIP fix + tests: `davidfowl/fix-resource-exclusion`

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with DockerComposeResourceExclusionTests.cs on the davidfowl/fix-resource-exclusion branch and inspect the BeforeStart, GetComputeResources, and ResourceMapping paths described in the issue. Compare the Docker Compose behavior with the Azure Container Apps, Azure App Service, and Kubernetes publisher patterns, keeping #11787 in view. Done means the named scenarios no longer crash or silently omit resources, with clear validation and corresponding publisher coverage.

Written by the indexing model from the issue text.

Assessment

Tech stack
azure, csharp, docker-compose, kubernetes
Domain
cloud, devops, infrastructure
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.